Merge "Flexiglass: Fix stack vertical scroll gestures on lockscreen" into main
diff --git a/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt b/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt
index 2af878e..daf991c 100644
--- a/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt
+++ b/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt
@@ -17,8 +17,7 @@
import android.app.AppOpsManager
import android.content.Context
-import androidx.benchmark.BenchmarkState
-import androidx.benchmark.junit4.BenchmarkRule
+import android.perftests.utils.PerfStatusReporter
import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.LargeTest
import org.junit.Before
@@ -34,7 +33,7 @@
* these APIs should be monitored closely for performance.
*/
class AppOpsPerfTest {
- @get:Rule val mBenchmarkRule: BenchmarkRule = BenchmarkRule()
+ @get:Rule val perfStatusReporter = PerfStatusReporter()
private lateinit var appOpsManager: AppOpsManager
private lateinit var opPackageName: String
private var opPackageUid: Int = 0
@@ -49,7 +48,7 @@
@Test
fun testNoteOp() {
- val state: BenchmarkState = mBenchmarkRule.getState()
+ val state = perfStatusReporter.benchmarkState
while (state.keepRunning()) {
appOpsManager.noteOp(
AppOpsManager.OPSTR_FINE_LOCATION,
@@ -63,7 +62,7 @@
@Test
fun testUnsafeCheckOp() {
- val state: BenchmarkState = mBenchmarkRule.getState()
+ val state = perfStatusReporter.benchmarkState
while (state.keepRunning()) {
appOpsManager.unsafeCheckOp(
AppOpsManager.OPSTR_FINE_LOCATION,
diff --git a/core/api/current.txt b/core/api/current.txt
index bbb3932..9d506b4 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -19910,7 +19910,6 @@
}
@FlaggedApi("com.android.internal.camera.flags.concert_mode_api") public final class ExtensionCaptureRequest {
- ctor public ExtensionCaptureRequest();
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> EFV_AUTO_ZOOM;
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> EFV_MAX_PADDING_ZOOM_FACTOR;
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> EFV_PADDING_ZOOM_FACTOR;
@@ -19923,7 +19922,6 @@
}
@FlaggedApi("com.android.internal.camera.flags.concert_mode_api") public final class ExtensionCaptureResult {
- ctor public ExtensionCaptureResult();
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> EFV_AUTO_ZOOM;
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<int[]> EFV_AUTO_ZOOM_PADDING_REGION;
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> EFV_MAX_PADDING_ZOOM_FACTOR;
diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt
index 1b0da05..e6a7ca5 100644
--- a/core/api/lint-baseline.txt
+++ b/core/api/lint-baseline.txt
@@ -245,14 +245,6 @@
Field 'ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE' is missing @BroadcastBehavior
-CompileTimeConstant: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_GIMBAL:
- All constants must be defined at compile time: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_GIMBAL
-CompileTimeConstant: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED:
- All constants must be defined at compile time: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED
-CompileTimeConstant: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_OFF:
- All constants must be defined at compile time: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_OFF
-
-
DeprecationMismatch: android.accounts.AccountManager#newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle):
Method android.accounts.AccountManager.newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match
DeprecationMismatch: android.app.Activity#enterPictureInPictureMode():
@@ -1095,14 +1087,6 @@
Method 'setGeolocationEnabled' documentation mentions permissions without declaring @RequiresPermission
-StaticUtils: ExtensionCaptureRequest:
- Fully-static utility classes must not have constructor
-StaticUtils: android.hardware.camera2.ExtensionCaptureRequest:
- Fully-static utility classes must not have constructor
-StaticUtils: android.hardware.camera2.ExtensionCaptureResult:
- Fully-static utility classes must not have constructor
-
-
Todo: android.hardware.camera2.params.StreamConfigurationMap:
Documentation mentions 'TODO'
Todo: android.provider.ContactsContract.RawContacts#newEntityIterator(android.database.Cursor):
@@ -1462,14 +1446,6 @@
UnflaggedApi: android.graphics.text.PositionedGlyphs#getWeightOverride(int):
New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getWeightOverride(int)
-UnflaggedApi: android.hardware.camera2.ExtensionCaptureRequest:
- New API must be flagged with @FlaggedApi: class android.hardware.camera2.ExtensionCaptureRequest
-UnflaggedApi: android.hardware.camera2.ExtensionCaptureRequest#ExtensionCaptureRequest():
- New API must be flagged with @FlaggedApi: constructor android.hardware.camera2.ExtensionCaptureRequest()
-UnflaggedApi: android.hardware.camera2.ExtensionCaptureResult:
- New API must be flagged with @FlaggedApi: class android.hardware.camera2.ExtensionCaptureResult
-UnflaggedApi: android.hardware.camera2.ExtensionCaptureResult#ExtensionCaptureResult():
- New API must be flagged with @FlaggedApi: constructor android.hardware.camera2.ExtensionCaptureResult()
UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_CAR:
New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_CAR
UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_COMPUTER:
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 79e2bd4..1c247a6 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -9291,11 +9291,11 @@
if (DEBUG_LIFECYCLE) Slog.v(TAG,
"dispatchMultiWindowModeChanged " + this + ": " + isInMultiWindowMode
+ " " + newConfig);
+ mIsInMultiWindowMode = isInMultiWindowMode;
mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode, newConfig);
if (mWindow != null) {
mWindow.onMultiWindowModeChanged();
}
- mIsInMultiWindowMode = isInMultiWindowMode;
onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
}
@@ -9304,11 +9304,11 @@
if (DEBUG_LIFECYCLE) Slog.v(TAG,
"dispatchPictureInPictureModeChanged " + this + ": " + isInPictureInPictureMode
+ " " + newConfig);
+ mIsInPictureInPictureMode = isInPictureInPictureMode;
mFragments.dispatchPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
if (mWindow != null) {
mWindow.onPictureInPictureModeChanged(isInPictureInPictureMode);
}
- mIsInPictureInPictureMode = isInPictureInPictureMode;
onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 9785252..83c3bf6 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -477,6 +477,11 @@
*/
public static final int OOM_ADJ_REASON_COMPONENT_DISABLED = 22;
+ /**
+ * Oom Adj Reason: Follow up update for time sensitive state evaluations.
+ */
+ public static final int OOM_ADJ_REASON_FOLLOW_UP = 23;
+
@IntDef(prefix = {"OOM_ADJ_REASON_"}, value = {
OOM_ADJ_REASON_NONE,
OOM_ADJ_REASON_ACTIVITY,
@@ -501,6 +506,7 @@
OOM_ADJ_REASON_EXECUTING_SERVICE,
OOM_ADJ_REASON_RESTRICTION_CHANGE,
OOM_ADJ_REASON_COMPONENT_DISABLED,
+ OOM_ADJ_REASON_FOLLOW_UP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface OomAdjReason {}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 15b13dc..ffb920b 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -757,6 +757,15 @@
void addStartInfoTimestamp(int key, long timestampNs, int userId);
/**
+ * Reports view related timestamps to be added to the calling apps most
+ * recent {@link ApplicationStartInfo}.
+ *
+ * @param renderThreadDrawStartTimeNs Clock monotonic time in nanoseconds of RenderThread draw start
+ * @param framePresentedTimeNs Clock monotonic time in nanoseconds of frame presented
+ */
+ oneway void reportStartInfoViewTimestamps(long renderThreadDrawStartTimeNs, long framePresentedTimeNs);
+
+ /**
* Return a list of {@link ApplicationExitInfo} records.
*
* <p class="note"> Note: System stores these historical information in a ring buffer, older
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index cf06416..5bc0ddc 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -42,6 +42,7 @@
import android.service.notification.ZenPolicy;
import android.app.AutomaticZenRule;
import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenDeviceEffects;
/** {@hide} */
interface INotificationManager
@@ -227,6 +228,7 @@
int getRuleInstanceCount(in ComponentName owner);
int getAutomaticZenRuleState(String id);
void setAutomaticZenRuleState(String id, in Condition condition);
+ void setManualZenRuleDeviceEffects(in ZenDeviceEffects effects);
byte[] getBackupPayload(int user);
void applyRestore(in byte[] payload, int user);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index e4310c1..bd80dc1 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -57,6 +57,7 @@
import android.service.notification.Adjustment;
import android.service.notification.Condition;
import android.service.notification.StatusBarNotification;
+import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenPolicy;
import android.util.Log;
@@ -1828,6 +1829,18 @@
throw e.rethrowFromSystemServer();
}
}
+ /**
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_MODES_UI)
+ public void setManualZenRuleDeviceEffects(@NonNull ZenDeviceEffects effects) {
+ INotificationManager service = getService();
+ try {
+ service.setManualZenRuleDeviceEffects(effects);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
/**
* For apps targeting {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} and above, the
diff --git a/core/java/android/app/contextualsearch/flags.aconfig b/core/java/android/app/contextualsearch/flags.aconfig
index 3385b2b..3b0c867 100644
--- a/core/java/android/app/contextualsearch/flags.aconfig
+++ b/core/java/android/app/contextualsearch/flags.aconfig
@@ -7,3 +7,9 @@
description: "Flag to enable the service"
bug: "309689654"
}
+flag {
+ name: "enable_token_refresh"
+ namespace: "machine_learning"
+ description: "Flag to refresh the token to the callback"
+ bug: "309689654"
+}
\ No newline at end of file
diff --git a/core/java/android/companion/ObservingDevicePresenceRequest.java b/core/java/android/companion/ObservingDevicePresenceRequest.java
index 11ea735..3150b87 100644
--- a/core/java/android/companion/ObservingDevicePresenceRequest.java
+++ b/core/java/android/companion/ObservingDevicePresenceRequest.java
@@ -180,6 +180,9 @@
* <p>Calling apps must use either this API or {@link #setAssociationId(int)},
* but not both.</p>
*
+ * <p>Calling app must hold the
+ * {@link AssociationRequest#DEVICE_PROFILE_AUTOMOTIVE_PROJECTION} profile.</p>
+ *
* @param uuid The ParcelUuid for observing device presence.
*/
@NonNull
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index e2159f7..37a2df8 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -200,7 +200,10 @@
throw new IllegalStateException(
"Exclusively one of logo resource or logo bitmap can be set");
}
- mPromptInfo.setLogo(logoRes, convertDrawableToBitmap(mContext.getDrawable(logoRes)));
+ if (logoRes != 0) {
+ mPromptInfo.setLogo(logoRes,
+ convertDrawableToBitmap(mContext.getDrawable(logoRes)));
+ }
return this;
}
@@ -219,11 +222,11 @@
@RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
@NonNull
public BiometricPrompt.Builder setLogoBitmap(@NonNull Bitmap logoBitmap) {
- if (mPromptInfo.getLogoRes() != -1) {
+ if (mPromptInfo.getLogoRes() != 0) {
throw new IllegalStateException(
"Exclusively one of logo resource or logo bitmap can be set");
}
- mPromptInfo.setLogo(-1, logoBitmap);
+ mPromptInfo.setLogo(0, logoBitmap);
return this;
}
@@ -832,7 +835,7 @@
* Gets the drawable resource of the logo for the prompt, as set by
* {@link Builder#setLogoRes(int)}. Currently for system applications use only.
*
- * @return The drawable resource of the logo, or -1 if the prompt has no logo resource set.
+ * @return The drawable resource of the logo, or 0 if the prompt has no logo resource set.
*/
@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT)
@RequiresPermission(SET_BIOMETRIC_DIALOG_ADVANCED)
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index f4a3c87..ba9f30d 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -33,7 +33,7 @@
*/
public class PromptInfo implements Parcelable {
- @DrawableRes private int mLogoRes = -1;
+ @DrawableRes private int mLogoRes;
@Nullable private Bitmap mLogoBitmap;
@Nullable private String mLogoDescription;
@NonNull private CharSequence mTitle;
@@ -187,7 +187,7 @@
* this permission.
*/
public boolean requiresAdvancedPermission() {
- if (mLogoRes != -1) {
+ if (mLogoRes != 0) {
return true;
} else if (mLogoBitmap != null) {
return true;
@@ -221,7 +221,7 @@
/**
* Sets logo res and bitmap
*
- * @param logoRes The logo res set by the app; Or -1 if the app sets bitmap directly.
+ * @param logoRes The logo res set by the app; Or 0 if the app sets bitmap directly.
* @param logoBitmap The bitmap from logoRes if the app sets logoRes; Or the bitmap set by the
* app directly.
*/
@@ -351,7 +351,7 @@
public Bitmap getLogoBitmap() {
// If mLogoRes has been set, return null since mLogoBitmap is from the res, but not from
// the app directly.
- return mLogoRes == -1 ? mLogoBitmap : null;
+ return mLogoRes == 0 ? mLogoBitmap : null;
}
public String getLogoDescription() {
diff --git a/core/java/android/hardware/camera2/ExtensionCaptureRequest.java b/core/java/android/hardware/camera2/ExtensionCaptureRequest.java
index c33956b..b681ce4 100644
--- a/core/java/android/hardware/camera2/ExtensionCaptureRequest.java
+++ b/core/java/android/hardware/camera2/ExtensionCaptureRequest.java
@@ -18,7 +18,6 @@
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
-import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureRequest.Key;
import android.hardware.camera2.impl.ExtensionKey;
@@ -43,6 +42,9 @@
@FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
public final class ExtensionCaptureRequest {
+ /** To avoid exposing constructor */
+ private ExtensionCaptureRequest() {}
+
/**
* <p>Used to apply an additional digital zoom factor for the
* {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
diff --git a/core/java/android/hardware/camera2/ExtensionCaptureResult.java b/core/java/android/hardware/camera2/ExtensionCaptureResult.java
index 95feb2f..b7ba78c 100644
--- a/core/java/android/hardware/camera2/ExtensionCaptureResult.java
+++ b/core/java/android/hardware/camera2/ExtensionCaptureResult.java
@@ -18,7 +18,6 @@
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
-import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraExtensionCharacteristics;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.CaptureResult.Key;
@@ -45,6 +44,9 @@
@FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
public final class ExtensionCaptureResult {
+ /** To avoid exposing constructor */
+ private ExtensionCaptureResult() {}
+
/**
* <p>The padding region for the
* {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
index 8898a4c..df057a1 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
@@ -105,7 +105,8 @@
try {
return cameraService.isSessionConfigurationWithParametersSupported(mCameraId,
- mTargetSdkVersion, config, mContext.getDeviceId(),
+ mTargetSdkVersion, config,
+ mContext.getDeviceId(),
mCameraManager.getDevicePolicyFromContext(mContext));
} catch (ServiceSpecificException e) {
throw ExceptionUtils.throwAsPublicException(e);
diff --git a/core/java/android/service/notification/ZenAdapters.java b/core/java/android/service/notification/ZenAdapters.java
index b249815..a122b71 100644
--- a/core/java/android/service/notification/ZenAdapters.java
+++ b/core/java/android/service/notification/ZenAdapters.java
@@ -33,7 +33,7 @@
.allowAlarms(policy.allowAlarms())
.allowCalls(
policy.allowCalls()
- ? notificationPolicySendersToZenPolicyPeopleType(
+ ? prioritySendersToPeopleType(
policy.allowCallsFrom())
: ZenPolicy.PEOPLE_TYPE_NONE)
.allowConversations(
@@ -45,7 +45,7 @@
.allowMedia(policy.allowMedia())
.allowMessages(
policy.allowMessages()
- ? notificationPolicySendersToZenPolicyPeopleType(
+ ? prioritySendersToPeopleType(
policy.allowMessagesFrom())
: ZenPolicy.PEOPLE_TYPE_NONE)
.allowReminders(policy.allowReminders())
@@ -71,7 +71,7 @@
/** Maps {@link ZenPolicy.PeopleType} enum to {@link Policy.PrioritySenders}. */
@Policy.PrioritySenders
- public static int zenPolicyPeopleTypeToNotificationPolicySenders(
+ public static int peopleTypeToPrioritySenders(
@ZenPolicy.PeopleType int zpPeopleType, @Policy.PrioritySenders int defaultResult) {
switch (zpPeopleType) {
case ZenPolicy.PEOPLE_TYPE_ANYONE:
@@ -87,7 +87,7 @@
/** Maps {@link Policy.PrioritySenders} enum to {@link ZenPolicy.PeopleType}. */
@ZenPolicy.PeopleType
- public static int notificationPolicySendersToZenPolicyPeopleType(
+ public static int prioritySendersToPeopleType(
@Policy.PrioritySenders int npPrioritySenders) {
switch (npPrioritySenders) {
case Policy.PRIORITY_SENDERS_ANY:
diff --git a/core/java/android/service/notification/ZenDeviceEffects.aidl b/core/java/android/service/notification/ZenDeviceEffects.aidl
new file mode 100644
index 0000000..e635493
--- /dev/null
+++ b/core/java/android/service/notification/ZenDeviceEffects.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+parcelable ZenDeviceEffects;
+
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 610a317..7a0c016 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -24,9 +24,26 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
-import static android.service.notification.ZenAdapters.notificationPolicySendersToZenPolicyPeopleType;
+import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+import static android.service.notification.ZenAdapters.peopleTypeToPrioritySenders;
+import static android.service.notification.ZenAdapters.prioritySendersToPeopleType;
import static android.service.notification.ZenAdapters.zenPolicyConversationSendersToNotificationPolicy;
-import static android.service.notification.ZenAdapters.zenPolicyPeopleTypeToNotificationPolicySenders;
+import static android.service.notification.ZenModeConfig.EventInfo.REPLY_YES_OR_MAYBE;
+import static android.service.notification.ZenPolicy.PEOPLE_TYPE_STARRED;
+import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_ALARMS;
+import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_CALLS;
+import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_EVENTS;
+import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_MEDIA;
+import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_MESSAGES;
+import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_REMINDERS;
+import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS;
+import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_SYSTEM;
+import static android.service.notification.ZenPolicy.STATE_ALLOW;
+import static android.service.notification.ZenPolicy.STATE_DISALLOW;
+import static android.service.notification.ZenPolicy.VISUAL_EFFECT_AMBIENT;
+import static android.service.notification.ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT;
+import static android.service.notification.ZenPolicy.VISUAL_EFFECT_LIGHTS;
+import static android.service.notification.ZenPolicy.VISUAL_EFFECT_PEEK;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -58,6 +75,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -320,31 +338,107 @@
@UnsupportedAppUsage
public ZenModeConfig() {
+ if (Flags.modesUi()) {
+ ensureManualZenRule();
+ }
}
public ZenModeConfig(Parcel source) {
- allowCalls = source.readInt() == 1;
- allowRepeatCallers = source.readInt() == 1;
- allowMessages = source.readInt() == 1;
- allowReminders = source.readInt() == 1;
- allowEvents = source.readInt() == 1;
- allowCallsFrom = source.readInt();
- allowMessagesFrom = source.readInt();
+ if (!Flags.modesUi()) {
+ allowCalls = source.readInt() == 1;
+ allowRepeatCallers = source.readInt() == 1;
+ allowMessages = source.readInt() == 1;
+ allowReminders = source.readInt() == 1;
+ allowEvents = source.readInt() == 1;
+ allowCallsFrom = source.readInt();
+ allowMessagesFrom = source.readInt();
+ }
user = source.readInt();
manualRule = source.readParcelable(null, ZenRule.class);
readRulesFromParcel(automaticRules, source);
if (Flags.modesApi()) {
readRulesFromParcel(deletedRules, source);
}
- allowAlarms = source.readInt() == 1;
- allowMedia = source.readInt() == 1;
- allowSystem = source.readInt() == 1;
- suppressedVisualEffects = source.readInt();
+ if (!Flags.modesUi()) {
+ allowAlarms = source.readInt() == 1;
+ allowMedia = source.readInt() == 1;
+ allowSystem = source.readInt() == 1;
+ suppressedVisualEffects = source.readInt();
+ }
areChannelsBypassingDnd = source.readInt() == 1;
- allowConversations = source.readBoolean();
- allowConversationsFrom = source.readInt();
- if (Flags.modesApi()) {
- allowPriorityChannels = source.readBoolean();
+ if (!Flags.modesUi()) {
+ allowConversations = source.readBoolean();
+ allowConversationsFrom = source.readInt();
+ if (Flags.modesApi()) {
+ allowPriorityChannels = source.readBoolean();
+ }
+ }
+ }
+
+ public static ZenPolicy getDefaultZenPolicy() {
+ ZenPolicy policy = new ZenPolicy.Builder()
+ .allowAlarms(true)
+ .allowMedia(true)
+ .allowSystem(false)
+ .allowCalls(PEOPLE_TYPE_STARRED)
+ .allowMessages(PEOPLE_TYPE_STARRED)
+ .allowReminders(false)
+ .allowEvents(false)
+ .allowRepeatCallers(true)
+ .allowConversations(CONVERSATION_SENDERS_IMPORTANT)
+ .showAllVisualEffects()
+ .showVisualEffect(VISUAL_EFFECT_FULL_SCREEN_INTENT, false)
+ .showVisualEffect(VISUAL_EFFECT_LIGHTS, false)
+ .showVisualEffect(VISUAL_EFFECT_PEEK, false)
+ .showVisualEffect(VISUAL_EFFECT_AMBIENT, false)
+ .allowPriorityChannels(true)
+ .build();
+ return policy;
+ }
+
+ public static ZenModeConfig getDefaultConfig() {
+ ZenModeConfig config = new ZenModeConfig();
+
+ EventInfo eventInfo = new EventInfo();
+ eventInfo.reply = REPLY_YES_OR_MAYBE;
+ ZenRule events = new ZenRule();
+ events.id = EVENTS_DEFAULT_RULE_ID;
+ events.conditionId = toEventConditionId(eventInfo);
+ events.component = ComponentName.unflattenFromString(
+ "android/com.android.server.notification.EventConditionProvider");
+ events.enabled = false;
+ events.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ events.pkg = "android";
+ config.automaticRules.put(EVENTS_DEFAULT_RULE_ID, events);
+
+ ScheduleInfo scheduleInfo = new ScheduleInfo();
+ scheduleInfo.days = new int[] {1, 2, 3, 4, 5, 6, 7};
+ scheduleInfo.startHour = 22;
+ scheduleInfo.endHour = 7;
+ scheduleInfo.exitAtAlarm = true;
+ ZenRule sleeping = new ZenRule();
+ sleeping.id = EVERY_NIGHT_DEFAULT_RULE_ID;
+ sleeping.conditionId = toScheduleConditionId(scheduleInfo);
+ sleeping.component = ComponentName.unflattenFromString(
+ "android/com.android.server.notification.ScheduleConditionProvider");
+ sleeping.enabled = false;
+ sleeping.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ sleeping.pkg = "android";
+ config.automaticRules.put(EVERY_NIGHT_DEFAULT_RULE_ID, sleeping);
+
+ return config;
+ }
+
+ void ensureManualZenRule() {
+ if (manualRule == null) {
+ final ZenRule newRule = new ZenRule();
+ newRule.type = AutomaticZenRule.TYPE_OTHER;
+ newRule.enabled = true;
+ newRule.conditionId = Uri.EMPTY;
+ newRule.allowManualInvocation = true;
+ newRule.zenPolicy = getDefaultZenPolicy();
+ newRule.pkg = "android";
+ manualRule = newRule;
}
}
@@ -363,28 +457,34 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(allowCalls ? 1 : 0);
- dest.writeInt(allowRepeatCallers ? 1 : 0);
- dest.writeInt(allowMessages ? 1 : 0);
- dest.writeInt(allowReminders ? 1 : 0);
- dest.writeInt(allowEvents ? 1 : 0);
- dest.writeInt(allowCallsFrom);
- dest.writeInt(allowMessagesFrom);
+ if (!Flags.modesUi()) {
+ dest.writeInt(allowCalls ? 1 : 0);
+ dest.writeInt(allowRepeatCallers ? 1 : 0);
+ dest.writeInt(allowMessages ? 1 : 0);
+ dest.writeInt(allowReminders ? 1 : 0);
+ dest.writeInt(allowEvents ? 1 : 0);
+ dest.writeInt(allowCallsFrom);
+ dest.writeInt(allowMessagesFrom);
+ }
dest.writeInt(user);
dest.writeParcelable(manualRule, 0);
writeRulesToParcel(automaticRules, dest);
if (Flags.modesApi()) {
writeRulesToParcel(deletedRules, dest);
}
- dest.writeInt(allowAlarms ? 1 : 0);
- dest.writeInt(allowMedia ? 1 : 0);
- dest.writeInt(allowSystem ? 1 : 0);
- dest.writeInt(suppressedVisualEffects);
+ if (!Flags.modesUi()) {
+ dest.writeInt(allowAlarms ? 1 : 0);
+ dest.writeInt(allowMedia ? 1 : 0);
+ dest.writeInt(allowSystem ? 1 : 0);
+ dest.writeInt(suppressedVisualEffects);
+ }
dest.writeInt(areChannelsBypassingDnd ? 1 : 0);
- dest.writeBoolean(allowConversations);
- dest.writeInt(allowConversationsFrom);
- if (Flags.modesApi()) {
- dest.writeBoolean(allowPriorityChannels);
+ if (!Flags.modesUi()) {
+ dest.writeBoolean(allowConversations);
+ dest.writeInt(allowConversationsFrom);
+ if (Flags.modesApi()) {
+ dest.writeBoolean(allowPriorityChannels);
+ }
}
}
@@ -408,35 +508,251 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[')
- .append("user=").append(user)
- .append(",allowAlarms=").append(allowAlarms)
- .append(",allowMedia=").append(allowMedia)
- .append(",allowSystem=").append(allowSystem)
- .append(",allowReminders=").append(allowReminders)
- .append(",allowEvents=").append(allowEvents)
- .append(",allowCalls=").append(allowCalls)
- .append(",allowRepeatCallers=").append(allowRepeatCallers)
- .append(",allowMessages=").append(allowMessages)
- .append(",allowConversations=").append(allowConversations)
- .append(",allowCallsFrom=").append(sourceToString(allowCallsFrom))
- .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
- .append(",allowConvFrom=").append(ZenPolicy.conversationTypeToString
- (allowConversationsFrom))
- .append(",suppressedVisualEffects=").append(suppressedVisualEffects);
+ .append("user=").append(user);
+ if (!Flags.modesUi()) {
+ sb.append(",allowAlarms=").append(allowAlarms)
+ .append(",allowMedia=").append(allowMedia)
+ .append(",allowSystem=").append(allowSystem)
+ .append(",allowReminders=").append(allowReminders)
+ .append(",allowEvents=").append(allowEvents)
+ .append(",allowCalls=").append(allowCalls)
+ .append(",allowRepeatCallers=").append(allowRepeatCallers)
+ .append(",allowMessages=").append(allowMessages)
+ .append(",allowConversations=").append(allowConversations)
+ .append(",allowCallsFrom=").append(sourceToString(allowCallsFrom))
+ .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
+ .append(",allowConvFrom=").append(ZenPolicy.conversationTypeToString
+ (allowConversationsFrom))
+ .append("\nsuppressedVisualEffects=").append(suppressedVisualEffects);
+ }
if (Flags.modesApi()) {
- sb.append(",hasPriorityChannels=").append(areChannelsBypassingDnd);
+ sb.append("\nhasPriorityChannels=").append(areChannelsBypassingDnd);
sb.append(",allowPriorityChannels=").append(allowPriorityChannels);
} else {
- sb.append(",areChannelsBypassingDnd=").append(areChannelsBypassingDnd);
+ sb.append("\nareChannelsBypassingDnd=").append(areChannelsBypassingDnd);
}
- sb.append(",\nautomaticRules=").append(rulesToString(automaticRules))
- .append(",\nmanualRule=").append(manualRule);
+ sb.append(",\nautomaticRules=").append(rulesToString(automaticRules));
+ sb.append(",\nmanualRule=").append(manualRule);
if (Flags.modesApi()) {
sb.append(",\ndeletedRules=").append(rulesToString(deletedRules));
}
return sb.append(']').toString();
}
+ public boolean isAllowPriorityChannels() {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ return allowPriorityChannels;
+ }
+
+ public void setAllowPriorityChannels(boolean allowPriorityChannels) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ this.allowPriorityChannels = allowPriorityChannels;
+ }
+ }
+
+ public int getSuppressedVisualEffects() {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ return this.suppressedVisualEffects;
+ }
+ }
+
+ public void setSuppressedVisualEffects(int suppressedVisualEffects) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ this.suppressedVisualEffects = suppressedVisualEffects;
+ }
+ }
+
+ public @ZenPolicy.ConversationSenders int getAllowConversationsFrom() {
+ if (Flags.modesUi()) {
+ return manualRule.zenPolicy.getPriorityConversationSenders();
+ }
+ return allowConversationsFrom;
+ }
+
+ public void setAllowConversationsFrom(
+ @ZenPolicy.ConversationSenders int allowConversationsFrom) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ this.allowConversationsFrom = allowConversationsFrom;
+ }
+ }
+
+ public void setAllowConversations(boolean allowConversations) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ this.allowConversations = allowConversations;
+ }
+ }
+
+ public boolean isAllowConversations() {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ return allowConversations;
+ }
+
+ public @Policy.PrioritySenders int getAllowMessagesFrom() {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ return allowMessagesFrom;
+ }
+
+ public void setAllowMessagesFrom(@Policy.PrioritySenders int allowMessagesFrom) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ this.allowMessagesFrom = allowMessagesFrom;
+ }
+ }
+
+ public void setAllowMessages(boolean allowMessages) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ this.allowMessages = allowMessages;
+ }
+
+ public @Policy.PrioritySenders int getAllowCallsFrom() {
+ if (Flags.modesUi()) {
+ return peopleTypeToPrioritySenders(
+ manualRule.zenPolicy.getPriorityCallSenders(), DEFAULT_CALLS_SOURCE);
+ }
+ return allowCallsFrom;
+ }
+
+ public void setAllowCallsFrom(@Policy.PrioritySenders int allowCallsFrom) {
+ if (Flags.modesUi()) {
+ manualRule.zenPolicy = new ZenPolicy.Builder(manualRule.zenPolicy)
+ .allowCalls(prioritySendersToPeopleType(allowCallsFrom))
+ .build();
+ } else {
+ this.allowCallsFrom = allowCallsFrom;
+ }
+ }
+
+ public void setAllowCalls(boolean allowCalls) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ this.allowCalls = allowCalls;
+ }
+
+ public boolean isAllowEvents() {
+ if (Flags.modesUi()) {
+ return manualRule.zenPolicy.isCategoryAllowed(
+ ZenPolicy.PRIORITY_CATEGORY_EVENTS, false);
+ }
+ return allowEvents;
+ }
+
+ public void setAllowEvents(boolean allowEvents) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ this.allowEvents = allowEvents;
+ }
+ }
+
+ public boolean isAllowReminders() {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ return allowReminders;
+ }
+
+ public void setAllowReminders(boolean allowReminders) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ this.allowReminders = allowReminders;
+ }
+ }
+
+ public boolean isAllowMessages() {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ return allowMessages;
+ }
+
+ public boolean isAllowRepeatCallers() {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ return allowRepeatCallers;
+ }
+
+ public void setAllowRepeatCallers(boolean allowRepeatCallers) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ this.allowRepeatCallers = allowRepeatCallers;
+ }
+ }
+
+ public boolean isAllowSystem() {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ return allowSystem;
+ }
+
+ public void setAllowSystem(boolean allowSystem) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ this.allowSystem = allowSystem;
+ }
+ }
+
+ public boolean isAllowMedia() {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ return allowMedia;
+ }
+
+ public void setAllowMedia(boolean allowMedia) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ this.allowMedia = allowMedia;
+ }
+ }
+
+ public boolean isAllowAlarms() {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ return allowAlarms;
+ }
+
+ public void setAllowAlarms(boolean allowAlarms) {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ } else {
+ this.allowAlarms = allowAlarms;
+ }
+ }
+
+ public boolean isAllowCalls() {
+ if (Flags.modesUi()) {
+ throw new IllegalStateException("can't be used with modesUI flag");
+ }
+ return allowCalls;
+ }
+
private static String rulesToString(ArrayMap<String, ZenRule> ruleList) {
if (ruleList.isEmpty()) {
return "{}";
@@ -512,6 +828,8 @@
if (!(o instanceof ZenModeConfig)) return false;
if (o == this) return true;
final ZenModeConfig other = (ZenModeConfig) o;
+ // The policy fields that live on config are compared directly because the fields will
+ // contain data until MODES_UI is rolled out/cleaned up.
boolean eq = other.allowAlarms == allowAlarms
&& other.allowMedia == allowMedia
&& other.allowSystem == allowSystem
@@ -539,6 +857,8 @@
@Override
public int hashCode() {
+ // The policy fields that live on config are compared directly because the fields will
+ // contain data until MODES_UI is rolled out/cleaned up.
if (Flags.modesApi()) {
return Objects.hash(allowAlarms, allowMedia, allowSystem, allowCalls,
allowRepeatCallers, allowMessages,
@@ -619,9 +939,14 @@
rt.version = safeInt(parser, ZEN_ATT_VERSION, getCurrentXmlVersion());
rt.user = safeInt(parser, ZEN_ATT_USER, rt.user);
boolean readSuppressedEffects = false;
+ boolean readManualRule = false;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
+ if (Flags.modesUi() && !readManualRule) {
+ // migrate from fields on config into manual rule
+ rt.manualRule.zenPolicy = rt.toZenPolicy();
+ }
return rt;
}
if (type == XmlPullParser.START_TAG) {
@@ -693,6 +1018,9 @@
DEFAULT_SUPPRESSED_VISUAL_EFFECTS);
} else if (MANUAL_TAG.equals(tag)) {
rt.manualRule = readRuleXml(parser);
+ if (rt.manualRule != null) {
+ readManualRule = true;
+ }
} else if (AUTOMATIC_TAG.equals(tag)
|| (Flags.modesApi() && AUTOMATIC_DELETED_TAG.equals(tag))) {
final String id = parser.getAttributeValue(null, RULE_ATT_ID);
@@ -742,6 +1070,9 @@
? Integer.toString(xmlVersion) : Integer.toString(version));
out.attributeInt(null, ZEN_ATT_USER, user);
out.startTag(null, ALLOW_TAG);
+ // From MODES_UI these fields are only read if the flag has transitioned from off to on
+ // However, we will continue to write these fields until the flag is cleaned up so it's
+ // possible to turn the flag off without losing user data
out.attributeBoolean(null, ALLOW_ATT_CALLS, allowCalls);
out.attributeBoolean(null, ALLOW_ATT_REPEAT_CALLERS, allowRepeatCallers);
out.attributeBoolean(null, ALLOW_ATT_MESSAGES, allowMessages);
@@ -816,11 +1147,11 @@
rt.enabler = parser.getAttributeValue(null, RULE_ATT_ENABLER);
rt.condition = readConditionXml(parser);
- if (!Flags.modesApi() && rt.zenMode != Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ if (!Flags.modesApi() && rt.zenMode != ZEN_MODE_IMPORTANT_INTERRUPTIONS
&& Condition.isValidId(rt.conditionId, SYSTEM_AUTHORITY)) {
// all default rules and user created rules updated to zenMode important interruptions
Slog.i(TAG, "Updating zenMode of automatic rule " + rt.name);
- rt.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ rt.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
}
rt.modified = safeBoolean(parser, RULE_ATT_MODIFIED, false);
rt.zenPolicy = readZenPolicyXml(parser);
@@ -952,7 +1283,7 @@
if (Flags.modesApi()) {
final int channels = safeInt(parser, ALLOW_ATT_CHANNELS, ZenPolicy.STATE_UNSET);
if (channels != ZenPolicy.STATE_UNSET) {
- builder.allowPriorityChannels(channels == ZenPolicy.STATE_ALLOW);
+ builder.allowPriorityChannels(channels == STATE_ALLOW);
policySet = true;
}
}
@@ -966,7 +1297,7 @@
policySet = true;
}
if (repeatCallers != ZenPolicy.STATE_UNSET) {
- builder.allowRepeatCallers(repeatCallers == ZenPolicy.STATE_ALLOW);
+ builder.allowRepeatCallers(repeatCallers == STATE_ALLOW);
policySet = true;
}
if (conversations != ZenPolicy.CONVERSATION_SENDERS_UNSET) {
@@ -974,23 +1305,23 @@
policySet = true;
}
if (alarms != ZenPolicy.STATE_UNSET) {
- builder.allowAlarms(alarms == ZenPolicy.STATE_ALLOW);
+ builder.allowAlarms(alarms == STATE_ALLOW);
policySet = true;
}
if (media != ZenPolicy.STATE_UNSET) {
- builder.allowMedia(media == ZenPolicy.STATE_ALLOW);
+ builder.allowMedia(media == STATE_ALLOW);
policySet = true;
}
if (system != ZenPolicy.STATE_UNSET) {
- builder.allowSystem(system == ZenPolicy.STATE_ALLOW);
+ builder.allowSystem(system == STATE_ALLOW);
policySet = true;
}
if (events != ZenPolicy.STATE_UNSET) {
- builder.allowEvents(events == ZenPolicy.STATE_ALLOW);
+ builder.allowEvents(events == STATE_ALLOW);
policySet = true;
}
if (reminders != ZenPolicy.STATE_UNSET) {
- builder.allowReminders(reminders == ZenPolicy.STATE_ALLOW);
+ builder.allowReminders(reminders == STATE_ALLOW);
policySet = true;
}
@@ -1005,31 +1336,31 @@
ZenPolicy.STATE_UNSET);
if (fullScreenIntent != ZenPolicy.STATE_UNSET) {
- builder.showFullScreenIntent(fullScreenIntent == ZenPolicy.STATE_ALLOW);
+ builder.showFullScreenIntent(fullScreenIntent == STATE_ALLOW);
policySet = true;
}
if (lights != ZenPolicy.STATE_UNSET) {
- builder.showLights(lights == ZenPolicy.STATE_ALLOW);
+ builder.showLights(lights == STATE_ALLOW);
policySet = true;
}
if (peek != ZenPolicy.STATE_UNSET) {
- builder.showPeeking(peek == ZenPolicy.STATE_ALLOW);
+ builder.showPeeking(peek == STATE_ALLOW);
policySet = true;
}
if (statusBar != ZenPolicy.STATE_UNSET) {
- builder.showStatusBarIcons(statusBar == ZenPolicy.STATE_ALLOW);
+ builder.showStatusBarIcons(statusBar == STATE_ALLOW);
policySet = true;
}
if (badges != ZenPolicy.STATE_UNSET) {
- builder.showBadges(badges == ZenPolicy.STATE_ALLOW);
+ builder.showBadges(badges == STATE_ALLOW);
policySet = true;
}
if (ambient != ZenPolicy.STATE_UNSET) {
- builder.showInAmbientDisplay(ambient == ZenPolicy.STATE_ALLOW);
+ builder.showInAmbientDisplay(ambient == STATE_ALLOW);
policySet = true;
}
if (notificationList != ZenPolicy.STATE_UNSET) {
- builder.showInNotificationList(notificationList == ZenPolicy.STATE_ALLOW);
+ builder.showInNotificationList(notificationList == STATE_ALLOW);
policySet = true;
}
@@ -1266,17 +1597,22 @@
}
};
+ public ZenPolicy getZenPolicy() {
+ return Flags.modesUi() ? manualRule.zenPolicy : toZenPolicy();
+ }
+
/**
* Converts a ZenModeConfig to a ZenPolicy
*/
- public ZenPolicy toZenPolicy() {
+ @VisibleForTesting
+ ZenPolicy toZenPolicy() {
ZenPolicy.Builder builder = new ZenPolicy.Builder()
.allowCalls(allowCalls
- ? notificationPolicySendersToZenPolicyPeopleType(allowCallsFrom)
+ ? prioritySendersToPeopleType(allowCallsFrom)
: ZenPolicy.PEOPLE_TYPE_NONE)
.allowRepeatCallers(allowRepeatCallers)
.allowMessages(allowMessages
- ? notificationPolicySendersToZenPolicyPeopleType(allowMessagesFrom)
+ ? prioritySendersToPeopleType(allowMessagesFrom)
: ZenPolicy.PEOPLE_TYPE_NONE)
.allowReminders(allowReminders)
.allowEvents(allowEvents)
@@ -1336,7 +1672,7 @@
if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_MESSAGES,
isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_MESSAGES, defaultPolicy))) {
priorityCategories |= Policy.PRIORITY_CATEGORY_MESSAGES;
- messageSenders = zenPolicyPeopleTypeToNotificationPolicySenders(
+ messageSenders = peopleTypeToPrioritySenders(
zenPolicy.getPriorityMessageSenders(), messageSenders);
}
@@ -1352,7 +1688,7 @@
if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CALLS,
isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_CALLS, defaultPolicy))) {
priorityCategories |= Policy.PRIORITY_CATEGORY_CALLS;
- callSenders = zenPolicyPeopleTypeToNotificationPolicySenders(
+ callSenders = peopleTypeToPrioritySenders(
zenPolicy.getPriorityCallSenders(), callSenders);
}
@@ -1452,46 +1788,155 @@
return (policy.suppressedVisualEffects & visualEffect) == 0;
}
+ private boolean isVisualEffectAllowed(int suppressedVisualEffects, int visualEffect) {
+ return (suppressedVisualEffects & visualEffect) == 0;
+ }
+
public Policy toNotificationPolicy() {
int priorityCategories = 0;
int priorityCallSenders = Policy.PRIORITY_SENDERS_CONTACTS;
int priorityMessageSenders = Policy.PRIORITY_SENDERS_CONTACTS;
int priorityConversationSenders = Policy.CONVERSATION_SENDERS_IMPORTANT;
- if (allowConversations) {
- priorityCategories |= Policy.PRIORITY_CATEGORY_CONVERSATIONS;
- }
- if (allowCalls) {
- priorityCategories |= Policy.PRIORITY_CATEGORY_CALLS;
- }
- if (allowMessages) {
- priorityCategories |= Policy.PRIORITY_CATEGORY_MESSAGES;
- }
- if (allowEvents) {
- priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
- }
- if (allowReminders) {
- priorityCategories |= Policy.PRIORITY_CATEGORY_REMINDERS;
- }
- if (allowRepeatCallers) {
- priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
- }
- if (allowAlarms) {
- priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
- }
- if (allowMedia) {
- priorityCategories |= Policy.PRIORITY_CATEGORY_MEDIA;
- }
- if (allowSystem) {
- priorityCategories |= Policy.PRIORITY_CATEGORY_SYSTEM;
- }
- priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders);
- priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders);
- priorityConversationSenders = zenPolicyConversationSendersToNotificationPolicy(
- allowConversationsFrom, priorityConversationSenders);
+ int state = 0;
+ int suppressedVisualEffects = 0;
- int state = areChannelsBypassingDnd ? Policy.STATE_CHANNELS_BYPASSING_DND : 0;
- if (Flags.modesApi()) {
- state = Policy.policyState(areChannelsBypassingDnd, allowPriorityChannels);
+ if (Flags.modesUi()) {
+ if (manualRule.zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_EVENTS, false)) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
+ }
+ if (manualRule.zenPolicy.isCategoryAllowed(
+ ZenPolicy.PRIORITY_CATEGORY_REMINDERS, false)) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_REMINDERS;
+ }
+ if (manualRule.zenPolicy.isCategoryAllowed(
+ ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS, false)) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
+ }
+ if (manualRule.zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_ALARMS, false)) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
+ }
+ if (manualRule.zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_MEDIA, false)) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_MEDIA;
+ }
+ if (manualRule.zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_SYSTEM, false)) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_SYSTEM;
+ }
+
+ if (manualRule.zenPolicy.getPriorityCategoryConversations() == STATE_ALLOW) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_CONVERSATIONS;
+ }
+ priorityConversationSenders = zenPolicyConversationSendersToNotificationPolicy(
+ manualRule.zenPolicy.getPriorityConversationSenders(),
+ CONVERSATION_SENDERS_NONE);
+ if (manualRule.zenPolicy.getPriorityCategoryCalls() == STATE_ALLOW) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_CALLS;
+ }
+ priorityCallSenders = peopleTypeToPrioritySenders(
+ manualRule.zenPolicy.getPriorityCallSenders(), DEFAULT_CALLS_SOURCE);
+ if (manualRule.zenPolicy.getPriorityCategoryMessages() == STATE_ALLOW) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_MESSAGES;
+ }
+ priorityMessageSenders = peopleTypeToPrioritySenders(
+ manualRule.zenPolicy.getPriorityMessageSenders(), DEFAULT_SOURCE);
+
+ state = Policy.policyState(areChannelsBypassingDnd,
+ manualRule.zenPolicy.getPriorityChannelsAllowed() != STATE_DISALLOW);
+
+ boolean suppressFullScreenIntent = !manualRule.zenPolicy.isVisualEffectAllowed(
+ ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT,
+ isVisualEffectAllowed(DEFAULT_SUPPRESSED_VISUAL_EFFECTS,
+ ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT));
+
+ boolean suppressLights = !manualRule.zenPolicy.isVisualEffectAllowed(
+ ZenPolicy.VISUAL_EFFECT_LIGHTS,
+ isVisualEffectAllowed(DEFAULT_SUPPRESSED_VISUAL_EFFECTS,
+ ZenPolicy.VISUAL_EFFECT_LIGHTS));
+
+ boolean suppressAmbient = !manualRule.zenPolicy.isVisualEffectAllowed(
+ ZenPolicy.VISUAL_EFFECT_AMBIENT,
+ isVisualEffectAllowed(DEFAULT_SUPPRESSED_VISUAL_EFFECTS,
+ ZenPolicy.VISUAL_EFFECT_AMBIENT));
+
+ if (suppressFullScreenIntent && suppressLights && suppressAmbient) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+ }
+
+ if (suppressFullScreenIntent) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+ }
+
+ if (suppressLights) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
+ }
+
+ if (!manualRule.zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_PEEK,
+ isVisualEffectAllowed(DEFAULT_SUPPRESSED_VISUAL_EFFECTS,
+ ZenPolicy.VISUAL_EFFECT_PEEK))) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_PEEK;
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+ }
+
+ if (!manualRule.zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_STATUS_BAR,
+ isVisualEffectAllowed(DEFAULT_SUPPRESSED_VISUAL_EFFECTS,
+ ZenPolicy.VISUAL_EFFECT_STATUS_BAR))) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+ }
+
+ if (!manualRule.zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_BADGE,
+ isVisualEffectAllowed(DEFAULT_SUPPRESSED_VISUAL_EFFECTS,
+ ZenPolicy.VISUAL_EFFECT_BADGE))) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
+ }
+
+ if (suppressAmbient) {
+ suppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
+ }
+
+ if (!manualRule.zenPolicy.isVisualEffectAllowed(
+ ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST,
+ isVisualEffectAllowed(DEFAULT_SUPPRESSED_VISUAL_EFFECTS,
+ ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST))) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+ }
+ } else {
+ if (isAllowConversations()) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_CONVERSATIONS;
+ }
+ if (isAllowCalls()) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_CALLS;
+ }
+ if (isAllowMessages()) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_MESSAGES;
+ }
+ if (isAllowEvents()) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
+ }
+ if (isAllowReminders()) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_REMINDERS;
+ }
+ if (isAllowRepeatCallers()) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
+ }
+ if (isAllowAlarms()) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
+ }
+ if (isAllowMedia()) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_MEDIA;
+ }
+ if (isAllowSystem()) {
+ priorityCategories |= Policy.PRIORITY_CATEGORY_SYSTEM;
+ }
+ priorityCallSenders = sourceToPrioritySenders(getAllowCallsFrom(), priorityCallSenders);
+ priorityMessageSenders = sourceToPrioritySenders(
+ getAllowMessagesFrom(), priorityMessageSenders);
+ priorityConversationSenders = zenPolicyConversationSendersToNotificationPolicy(
+ getAllowConversationsFrom(), priorityConversationSenders);
+
+ state = areChannelsBypassingDnd ? Policy.STATE_CHANNELS_BYPASSING_DND : 0;
+ if (Flags.modesApi()) {
+ state = Policy.policyState(areChannelsBypassingDnd, allowPriorityChannels);
+ }
+ suppressedVisualEffects = getSuppressedVisualEffects();
}
return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders,
@@ -1544,31 +1989,38 @@
public void applyNotificationPolicy(Policy policy) {
if (policy == null) return;
- allowAlarms = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_ALARMS) != 0;
- allowMedia = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_MEDIA) != 0;
- allowSystem = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_SYSTEM) != 0;
- allowEvents = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_EVENTS) != 0;
- allowReminders = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REMINDERS) != 0;
- allowCalls = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_CALLS) != 0;
- allowMessages = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_MESSAGES) != 0;
- allowRepeatCallers = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REPEAT_CALLERS)
- != 0;
- allowCallsFrom = normalizePrioritySenders(policy.priorityCallSenders, allowCallsFrom);
- allowMessagesFrom = normalizePrioritySenders(policy.priorityMessageSenders,
- allowMessagesFrom);
- if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
- suppressedVisualEffects = policy.suppressedVisualEffects;
+ if (Flags.modesUi()) {
+ manualRule.zenPolicy = ZenAdapters.notificationPolicyToZenPolicy(policy);
+ } else {
+ setAllowAlarms((policy.priorityCategories & Policy.PRIORITY_CATEGORY_ALARMS) != 0);
+ allowMedia = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_MEDIA) != 0;
+ allowSystem = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_SYSTEM) != 0;
+ allowEvents = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_EVENTS) != 0;
+ allowReminders = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REMINDERS) != 0;
+ allowCalls = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_CALLS) != 0;
+ allowMessages = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_MESSAGES) != 0;
+ allowRepeatCallers =
+ (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REPEAT_CALLERS)
+ != 0;
+ allowCallsFrom = normalizePrioritySenders(policy.priorityCallSenders, allowCallsFrom);
+ allowMessagesFrom = normalizePrioritySenders(policy.priorityMessageSenders,
+ allowMessagesFrom);
+ if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
+ suppressedVisualEffects = policy.suppressedVisualEffects;
+ }
+ allowConversations = (policy.priorityCategories
+ & Policy.PRIORITY_CATEGORY_CONVERSATIONS) != 0;
+ allowConversationsFrom = normalizeConversationSenders(allowConversations,
+ policy.priorityConversationSenders,
+ allowConversationsFrom);
+ if (policy.state != Policy.STATE_UNSET) {
+ if (Flags.modesApi()) {
+ setAllowPriorityChannels(policy.allowPriorityChannels());
+ }
+ }
}
- allowConversations = (policy.priorityCategories
- & Policy.PRIORITY_CATEGORY_CONVERSATIONS) != 0;
- allowConversationsFrom = normalizeConversationSenders(allowConversations,
- policy.priorityConversationSenders,
- allowConversationsFrom);
if (policy.state != Policy.STATE_UNSET) {
areChannelsBypassingDnd = (policy.state & Policy.STATE_CHANNELS_BYPASSING_DND) != 0;
- if (Flags.modesApi()) {
- allowPriorityChannels = policy.allowPriorityChannels();
- }
}
}
@@ -1995,49 +2447,11 @@
return "";
}
- public static String getConditionSummary(Context context, ZenModeConfig config,
- int userHandle, boolean shortVersion) {
- return getConditionLine(context, config, userHandle, false /*useLine1*/, shortVersion);
- }
-
- private static String getConditionLine(Context context, ZenModeConfig config,
- int userHandle, boolean useLine1, boolean shortVersion) {
- if (config == null) return "";
- String summary = "";
- if (config.manualRule != null) {
- final Uri id = config.manualRule.conditionId;
- if (config.manualRule.enabler != null) {
- summary = getOwnerCaption(context, config.manualRule.enabler);
- } else {
- if (id == null) {
- summary = context.getString(com.android.internal.R.string.zen_mode_forever);
- } else {
- final long time = tryParseCountdownConditionId(id);
- Condition c = config.manualRule.condition;
- if (time > 0) {
- final long now = System.currentTimeMillis();
- final long span = time - now;
- c = toTimeCondition(context, time, Math.round(span / (float) MINUTES_MS),
- userHandle, shortVersion);
- }
- final String rt = c == null ? "" : useLine1 ? c.line1 : c.summary;
- summary = TextUtils.isEmpty(rt) ? "" : rt;
- }
- }
+ public boolean isManualActive() {
+ if (!Flags.modesUi()) {
+ return manualRule != null;
}
- for (ZenRule automaticRule : config.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
- if (summary.isEmpty()) {
- summary = automaticRule.name;
- } else {
- summary = context.getResources()
- .getString(R.string.zen_mode_rule_name_combination, summary,
- automaticRule.name);
- }
-
- }
- }
- return summary;
+ return manualRule != null && manualRule.isAutomaticActive();
}
public static class ZenRule implements Parcelable {
@@ -2401,7 +2815,7 @@
public static boolean isZenOverridingRinger(int zen, Policy consolidatedPolicy) {
return zen == Global.ZEN_MODE_NO_INTERRUPTIONS
|| zen == Global.ZEN_MODE_ALARMS
- || (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ || (zen == ZEN_MODE_IMPORTANT_INTERRUPTIONS
&& ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(consolidatedPolicy));
}
@@ -2410,21 +2824,40 @@
* This includes notification, ringer and system sounds
*/
public static boolean areAllPriorityOnlyRingerSoundsMuted(ZenModeConfig config) {
- boolean areChannelsBypassingDnd = config.areChannelsBypassingDnd;
- if (Flags.modesApi()) {
- areChannelsBypassingDnd = config.areChannelsBypassingDnd
- && config.allowPriorityChannels;
+ if (Flags.modesUi()) {
+ final ZenPolicy policy = config.manualRule.zenPolicy;
+ return !policy.isCategoryAllowed(PRIORITY_CATEGORY_REMINDERS, false)
+ && !policy.isCategoryAllowed(PRIORITY_CATEGORY_CALLS, false)
+ && !policy.isCategoryAllowed(PRIORITY_CATEGORY_MESSAGES, false)
+ && !policy.isCategoryAllowed(PRIORITY_CATEGORY_EVENTS, false)
+ && !policy.isCategoryAllowed(PRIORITY_CATEGORY_REPEAT_CALLERS, false)
+ && !policy.isCategoryAllowed(PRIORITY_CATEGORY_SYSTEM, false)
+ && !(config.areChannelsBypassingDnd && policy.getPriorityChannelsAllowed()
+ == STATE_ALLOW);
+
+ } else {
+ boolean areChannelsBypassingDnd = config.areChannelsBypassingDnd;
+ if (Flags.modesApi()) {
+ areChannelsBypassingDnd = config.areChannelsBypassingDnd
+ && config.isAllowPriorityChannels();
+ }
+ return !config.isAllowReminders() && !config.isAllowCalls() && !config.isAllowMessages()
+ && !config.isAllowEvents() && !config.isAllowRepeatCallers()
+ && !areChannelsBypassingDnd && !config.isAllowSystem();
}
- return !config.allowReminders && !config.allowCalls && !config.allowMessages
- && !config.allowEvents && !config.allowRepeatCallers
- && !areChannelsBypassingDnd && !config.allowSystem;
}
/**
* Determines whether dnd mutes all sounds
*/
public static boolean areAllZenBehaviorSoundsMuted(ZenModeConfig config) {
- return !config.allowAlarms && !config.allowMedia
+ if (Flags.modesUi()) {
+ final ZenPolicy policy = config.manualRule.zenPolicy;
+ return !policy.isCategoryAllowed(PRIORITY_CATEGORY_ALARMS, false)
+ && !policy.isCategoryAllowed(PRIORITY_CATEGORY_MEDIA, false)
+ && areAllPriorityOnlyRingerSoundsMuted(config);
+ }
+ return !config.isAllowAlarms() && !config.isAllowMedia()
&& areAllPriorityOnlyRingerSoundsMuted(config);
}
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 57d1b8d..ccec89b 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -496,9 +496,10 @@
if (delegatorPackageName == null) {
delegatorPackageName = view.getContext().getOpPackageName();
}
+ WeakReference<View> viewRef = new WeakReference<>(view);
Consumer<Boolean> consumer = delegationAccepted -> {
if (delegationAccepted) {
- onDelegationAccepted(view);
+ onDelegationAccepted(viewRef.get());
}
};
mImm.acceptStylusHandwritingDelegation(view, delegatorPackageName, view::post, consumer);
@@ -509,6 +510,10 @@
mState.mHandled = true;
mState.mShouldInitHandwriting = false;
}
+ if (view == null) {
+ // can be null if view was detached and was GCed.
+ return;
+ }
if (view instanceof TextView) {
((TextView) view).hideHint();
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a26150c..a11bb78 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -177,6 +177,7 @@
import android.graphics.RenderNode;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
+import android.hardware.SyncFence;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.display.DisplayManagerGlobal;
@@ -219,6 +220,7 @@
import android.view.InputDevice.InputSourceClass;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl.Transaction;
+import android.view.SurfaceControl.TransactionStats;
import android.view.View.AttachInfo;
import android.view.View.FocusDirection;
import android.view.View.MeasureSpec;
@@ -293,6 +295,7 @@
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* The top of a view hierarchy, implementing the needed protocol between View
@@ -1189,6 +1192,13 @@
private String mFpsTraceName;
private String mLargestViewTraceName;
+ private final boolean mAppStartInfoTimestampsFlagValue;
+ @GuardedBy("this")
+ private boolean mAppStartTimestampsSent = false;
+ private boolean mAppStartTrackingStarted = false;
+ private long mRenderThreadDrawStartTimeNs = -1;
+ private long mFirstFramePresentedTimeNs = -1;
+
private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
private static boolean sToolkitFrameRateFunctionEnablingReadOnlyFlagValue;
private static boolean sToolkitMetricsForFrameRateDecisionFlagValue;
@@ -1306,6 +1316,8 @@
} else {
mSensitiveContentProtectionService = null;
}
+
+ mAppStartInfoTimestampsFlagValue = android.app.Flags.appStartInfoTimestamps();
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -2578,6 +2590,12 @@
notifySurfaceDestroyed();
}
destroySurface();
+
+ // Reset so they can be sent again for warm starts.
+ mAppStartTimestampsSent = false;
+ mAppStartTrackingStarted = false;
+ mRenderThreadDrawStartTimeNs = -1;
+ mFirstFramePresentedTimeNs = -1;
}
}
}
@@ -4376,6 +4394,30 @@
reportDrawFinished(t, seqId);
}
});
+
+ // Only trigger once per {@link ViewRootImpl} instance, so don't add listener if
+ // {link mTransactionCompletedTimeNs} has already been set.
+ if (mAppStartInfoTimestampsFlagValue && !mAppStartTrackingStarted) {
+ mAppStartTrackingStarted = true;
+ Transaction transaction = new Transaction();
+ transaction.addTransactionCompletedListener(mExecutor,
+ new Consumer<TransactionStats>() {
+ @Override
+ public void accept(TransactionStats transactionStats) {
+ SyncFence presentFence = transactionStats.getPresentFence();
+ if (presentFence.awaitForever()) {
+ if (mFirstFramePresentedTimeNs == -1) {
+ // Only trigger once per {@link ViewRootImpl} instance.
+ mFirstFramePresentedTimeNs = presentFence.getSignalTime();
+ maybeSendAppStartTimes();
+ }
+ }
+ presentFence.close();
+ }
+ });
+ applyTransactionOnDraw(transaction);
+ }
+
if (DEBUG_BLAST) {
Log.d(mTag, "Setup new sync=" + mWmsRequestSyncGroup.getName());
}
@@ -4383,6 +4425,45 @@
mWmsRequestSyncGroup.add(this, null /* runnable */);
}
+ private void maybeSendAppStartTimes() {
+ synchronized (this) {
+ if (mAppStartTimestampsSent) {
+ // Don't send timestamps more than once.
+ return;
+ }
+
+ // If we already have {@link mRenderThreadDrawStartTimeNs} then pass it through, if not
+ // post to main thread and check if we have it there.
+ if (mRenderThreadDrawStartTimeNs != -1) {
+ sendAppStartTimesLocked();
+ } else {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (ViewRootImpl.this) {
+ if (mRenderThreadDrawStartTimeNs == -1) {
+ return;
+ }
+ sendAppStartTimesLocked();
+ }
+ }
+ });
+ }
+ }
+ }
+
+ @GuardedBy("this")
+ private void sendAppStartTimesLocked() {
+ try {
+ ActivityManager.getService().reportStartInfoViewTimestamps(
+ mRenderThreadDrawStartTimeNs, mFirstFramePresentedTimeNs);
+ mAppStartTimestampsSent = true;
+ } catch (RemoteException e) {
+ // Ignore, timestamps may be lost.
+ if (DBG) Log.d(TAG, "Exception attempting to report start timestamps.", e);
+ }
+ }
+
/**
* Helper used to notify the service to block projection when a sensitive
* view (the view displays sensitive content) is attached to the window.
@@ -5569,7 +5650,13 @@
registerCallbackForPendingTransactions();
}
+ long timeNs = SystemClock.uptimeNanos();
mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
+
+ // Only trigger once per {@link ViewRootImpl} instance.
+ if (mAppStartInfoTimestampsFlagValue && mRenderThreadDrawStartTimeNs == -1) {
+ mRenderThreadDrawStartTimeNs = timeNs;
+ }
} else {
// If we get here with a disabled & requested hardware renderer, something went
// wrong (an invalidate posted right before we destroyed the hardware surface
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 950dfee..199a69a 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -524,7 +524,7 @@
return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_AUTOFILL,
DEVICE_CONFIG_INCLUDE_INVISIBLE_VIEW_GROUP_IN_ASSIST_STRUCTURE,
- false);
+ true);
}
/** @hide */
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index 15ba1a1..6b60858 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -61,6 +61,11 @@
}
/** @hide */
+ public AutofillId(@NonNull AutofillId hostId, int virtualChildId, int sessionId) {
+ this(FLAG_IS_VIRTUAL_INT | FLAG_HAS_SESSION, hostId.mViewId, virtualChildId, sessionId);
+ }
+
+ /** @hide */
@TestApi
public AutofillId(@NonNull AutofillId hostId, long virtualChildId, int sessionId) {
this(FLAG_IS_VIRTUAL_LONG | FLAG_HAS_SESSION, hostId.mViewId, virtualChildId, sessionId);
@@ -236,9 +241,9 @@
public String toString() {
final StringBuilder builder = new StringBuilder().append(mViewId);
if (isVirtualInt()) {
- builder.append(':').append(mVirtualIntId);
+ builder.append(":i").append(mVirtualIntId);
} else if (isVirtualLong()) {
- builder.append(':').append(mVirtualLongId);
+ builder.append(":l").append(mVirtualLongId);
}
if (hasSession()) {
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index ad513f1..53d9429 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -193,6 +193,7 @@
@RequiresFeature(PackageManager.FEATURE_AUTOFILL)
public final class AutofillManager {
+ private static final boolean DBG = false;
private static final String TAG = "AutofillManager";
/**
@@ -2027,7 +2028,31 @@
if (!hasAutofillFeature()) {
return;
}
+ if (DBG) {
+ Log.v(TAG, "notifyValueChanged() called with virtualId:" + virtualId + " value:"
+ + value);
+ }
synchronized (mLock) {
+ if (mLastAutofilledData != null) {
+ AutofillId id = new AutofillId(view.getAutofillId(), virtualId, mSessionId);
+ if (mLastAutofilledData.containsKey(id)) {
+ if (Objects.equals(mLastAutofilledData.get(id), value)) {
+ // Indicates that the view was autofilled
+ if (sDebug) {
+ Log.v(TAG, "notifyValueChanged() virtual view autofilled successfully:"
+ + virtualId + " value:" + value);
+ }
+ try {
+ mService.setViewAutofilled(mSessionId, id, mContext.getUserId());
+ } catch (RemoteException e) {
+ // The failure could be a consequence of something going wrong on the
+ // server side. Do nothing here since it's just logging, but it's
+ // possible follow-up actions may fail.
+ Log.w(TAG, "RemoteException caught but ignored " + e);
+ }
+ }
+ }
+ }
if (!mEnabled || !isActiveLocked()) {
if (sVerbose) {
Log.v(TAG, "notifyValueChanged(" + view.getAutofillId() + ":" + virtualId
@@ -3114,6 +3139,10 @@
ArrayList<AutofillId> failedIds = new ArrayList<>();
+ if (mLastAutofilledData == null) {
+ mLastAutofilledData = new ParcelableMap(itemCount);
+ }
+
for (int i = 0; i < itemCount; i++) {
final AutofillId id = ids.get(i);
final AutofillValue value = values.get(i);
@@ -3126,6 +3155,9 @@
failedIds.add(id);
continue;
}
+ // Mark the view as to be autofilled with 'value'
+ mLastAutofilledData.put(id, value);
+
if (id.isVirtualInt()) {
if (virtualValues == null) {
// Most likely there will be just one view with virtual children.
@@ -3139,12 +3171,6 @@
}
valuesByParent.put(id.getVirtualChildIntId(), value);
} else {
- // Mark the view as to be autofilled with 'value'
- if (mLastAutofilledData == null) {
- mLastAutofilledData = new ParcelableMap(itemCount - i);
- }
- mLastAutofilledData.put(id, value);
-
view.autofill(value);
// Set as autofilled if the values match now, e.g. when the value was updated
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 2d4bb90..0c63e58 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -129,6 +129,7 @@
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
@@ -2630,13 +2631,17 @@
return false;
}
if (useDelegation) {
+ WeakReference<Executor> executorRef = new WeakReference<>(executor);
+ WeakReference<Consumer<Boolean>> callbackRef = new WeakReference<>(callback);
if (useCallback) {
IBooleanListener listener = new IBooleanListener.Stub() {
@Override
public void onResult(boolean value) {
- executor.execute(() -> {
- callback.accept(value);
- });
+ Executor executor = executorRef.get();
+ Consumer<Boolean> callback = callbackRef.get();
+ if (executor != null && callback != null) {
+ executor.execute(() -> callback.accept(value));
+ }
}
};
if (!IInputMethodManagerGlobalInvoker.acceptStylusHandwritingDelegationAsync(
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 40d760e..2194c89 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -537,13 +537,8 @@
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
- if (!isDestroyed()) {
- if (cb != null) {
- cb.onContentChanged();
- }
- if (mDecorContentParent != null) {
- mDecorContentParent.notifyContentChanged();
- }
+ if (cb != null && !isDestroyed()) {
+ cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
@@ -573,13 +568,8 @@
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
- if (!isDestroyed()) {
- if (cb != null) {
- cb.onContentChanged();
- }
- if (mDecorContentParent != null) {
- mDecorContentParent.notifyContentChanged();
- }
+ if (cb != null && !isDestroyed()) {
+ cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
@@ -596,13 +586,8 @@
mContentParent.addView(view, params);
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
- if (!isDestroyed()) {
- if (cb != null) {
- cb.onContentChanged();
- }
- if (mDecorContentParent != null) {
- mDecorContentParent.notifyContentChanged();
- }
+ if (cb != null && !isDestroyed()) {
+ cb.onContentChanged();
}
}
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index ff57fd4..6832825 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -898,13 +898,6 @@
mDecorToolbar.dismissPopupMenus();
}
- @Override
- public void notifyContentChanged() {
- mLastBaseContentInsets.setEmpty();
- mLastBaseInnerInsets = WindowInsets.CONSUMED;
- mLastInnerInsets = WindowInsets.CONSUMED;
- }
-
public static class LayoutParams extends MarginLayoutParams {
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
diff --git a/core/java/com/android/internal/widget/DecorContentParent.java b/core/java/com/android/internal/widget/DecorContentParent.java
index 8d6cfd1..ac524f9 100644
--- a/core/java/com/android/internal/widget/DecorContentParent.java
+++ b/core/java/com/android/internal/widget/DecorContentParent.java
@@ -22,7 +22,6 @@
import android.util.SparseArray;
import android.view.Menu;
import android.view.Window;
-
import com.android.internal.view.menu.MenuPresenter;
/**
@@ -50,5 +49,4 @@
void saveToolbarHierarchyState(SparseArray<Parcelable> toolbarStates);
void restoreToolbarHierarchyState(SparseArray<Parcelable> toolbarStates);
void dismissPopups();
- void notifyContentChanged();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
index 55f2dee..00262be 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
@@ -30,7 +30,7 @@
ArrayList<Operation> mOperations;
RemoteComposeState mRemoteComposeState = new RemoteComposeState();
-
+ TimeVariables mTimeVariables = new TimeVariables();
// Semantic version of the document
Version mVersion = new Version(0, 1, 0);
@@ -70,6 +70,7 @@
public void setWidth(int width) {
this.mWidth = width;
+ mRemoteComposeState.setWindowWidth(width);
}
public int getHeight() {
@@ -78,6 +79,8 @@
public void setHeight(int height) {
this.mHeight = height;
+ mRemoteComposeState.setWindowHeight(height);
+
}
public RemoteComposeBuffer getBuffer() {
@@ -111,21 +114,21 @@
/**
* Sets the way the player handles the content
*
- * @param scroll set the horizontal behavior (NONE|SCROLL_HORIZONTAL|SCROLL_VERTICAL)
+ * @param scroll set the horizontal behavior (NONE|SCROLL_HORIZONTAL|SCROLL_VERTICAL)
* @param alignment set the alignment of the content (TOP|CENTER|BOTTOM|START|END)
- * @param sizing set the type of sizing for the content (NONE|SIZING_LAYOUT|SIZING_SCALE)
- * @param mode set the mode of sizing, either LAYOUT modes or SCALE modes
- * the LAYOUT modes are:
- * - LAYOUT_MATCH_PARENT
- * - LAYOUT_WRAP_CONTENT
- * or adding an horizontal mode and a vertical mode:
- * - LAYOUT_HORIZONTAL_MATCH_PARENT
- * - LAYOUT_HORIZONTAL_WRAP_CONTENT
- * - LAYOUT_HORIZONTAL_FIXED
- * - LAYOUT_VERTICAL_MATCH_PARENT
- * - LAYOUT_VERTICAL_WRAP_CONTENT
- * - LAYOUT_VERTICAL_FIXED
- * The LAYOUT_*_FIXED modes will use the intrinsic document size
+ * @param sizing set the type of sizing for the content (NONE|SIZING_LAYOUT|SIZING_SCALE)
+ * @param mode set the mode of sizing, either LAYOUT modes or SCALE modes
+ * the LAYOUT modes are:
+ * - LAYOUT_MATCH_PARENT
+ * - LAYOUT_WRAP_CONTENT
+ * or adding an horizontal mode and a vertical mode:
+ * - LAYOUT_HORIZONTAL_MATCH_PARENT
+ * - LAYOUT_HORIZONTAL_WRAP_CONTENT
+ * - LAYOUT_HORIZONTAL_FIXED
+ * - LAYOUT_VERTICAL_MATCH_PARENT
+ * - LAYOUT_VERTICAL_WRAP_CONTENT
+ * - LAYOUT_VERTICAL_FIXED
+ * The LAYOUT_*_FIXED modes will use the intrinsic document size
*/
public void setRootContentBehavior(int scroll, int alignment, int sizing, int mode) {
this.mContentScroll = scroll;
@@ -138,8 +141,8 @@
* Given dimensions w x h of where to paint the content, returns the corresponding scale factor
* according to the contentSizing information
*
- * @param w horizontal dimension of the rendering area
- * @param h vertical dimension of the rendering area
+ * @param w horizontal dimension of the rendering area
+ * @param h vertical dimension of the rendering area
* @param scaleOutput will contain the computed scale factor
*/
public void computeScale(float w, float h, float[] scaleOutput) {
@@ -154,37 +157,43 @@
float scale = Math.min(1f, Math.min(scaleX, scaleY));
contentScaleX = scale;
contentScaleY = scale;
- } break;
+ }
+ break;
case RootContentBehavior.SCALE_FIT: {
float scaleX = w / mWidth;
float scaleY = h / mHeight;
float scale = Math.min(scaleX, scaleY);
contentScaleX = scale;
contentScaleY = scale;
- } break;
+ }
+ break;
case RootContentBehavior.SCALE_FILL_WIDTH: {
float scale = w / mWidth;
contentScaleX = scale;
contentScaleY = scale;
- } break;
+ }
+ break;
case RootContentBehavior.SCALE_FILL_HEIGHT: {
float scale = h / mHeight;
contentScaleX = scale;
contentScaleY = scale;
- } break;
+ }
+ break;
case RootContentBehavior.SCALE_CROP: {
float scaleX = w / mWidth;
float scaleY = h / mHeight;
float scale = Math.max(scaleX, scaleY);
contentScaleX = scale;
contentScaleY = scale;
- } break;
+ }
+ break;
case RootContentBehavior.SCALE_FILL_BOUNDS: {
float scaleX = w / mWidth;
float scaleY = h / mHeight;
contentScaleX = scaleX;
contentScaleY = scaleY;
- } break;
+ }
+ break;
default:
// nothing
}
@@ -197,10 +206,10 @@
* Given dimensions w x h of where to paint the content, returns the corresponding translation
* according to the contentAlignment information
*
- * @param w horizontal dimension of the rendering area
- * @param h vertical dimension of the rendering area
- * @param contentScaleX the horizontal scale we are going to use for the content
- * @param contentScaleY the vertical scale we are going to use for the content
+ * @param w horizontal dimension of the rendering area
+ * @param h vertical dimension of the rendering area
+ * @param contentScaleX the horizontal scale we are going to use for the content
+ * @param contentScaleY the vertical scale we are going to use for the content
* @param translateOutput will contain the computed translation
*/
private void computeTranslate(float w, float h, float contentScaleX, float contentScaleY,
@@ -215,26 +224,32 @@
switch (horizontalContentAlignment) {
case RootContentBehavior.ALIGNMENT_START: {
// nothing
- } break;
+ }
+ break;
case RootContentBehavior.ALIGNMENT_HORIZONTAL_CENTER: {
translateX = (w - contentWidth) / 2f;
- } break;
+ }
+ break;
case RootContentBehavior.ALIGNMENT_END: {
translateX = w - contentWidth;
- } break;
+ }
+ break;
default:
// nothing (same as alignment_start)
}
switch (verticalContentAlignment) {
case RootContentBehavior.ALIGNMENT_TOP: {
// nothing
- } break;
+ }
+ break;
case RootContentBehavior.ALIGNMENT_VERTICAL_CENTER: {
translateY = (h - contentHeight) / 2f;
- } break;
+ }
+ break;
case RootContentBehavior.ALIGNMENT_BOTTOM: {
translateY = h - contentHeight;
- } break;
+ }
+ break;
default:
// nothing (same as alignment_top)
}
@@ -291,7 +306,13 @@
this.mMetadata = metadata;
}
- public boolean contains(float x, float y) {
+ /**
+ * Returns true if x,y coordinate is within bounds
+ * @param x x-coordinate
+ * @param y y-coordinate
+ * @return x,y coordinate is within bounds
+ */
+ public boolean contains(float x, float y) {
return x >= mLeft && x < mRight
&& y >= mTop && y < mBottom;
}
@@ -341,16 +362,22 @@
public void initializeContext(RemoteContext context) {
mRemoteComposeState.reset();
mClickAreas.clear();
-
+ mRemoteComposeState.setNextId(RemoteComposeState.START_ID);
context.mDocument = this;
context.mRemoteComposeState = mRemoteComposeState;
-
// mark context to be in DATA mode, which will skip the painting ops.
context.mMode = RemoteContext.ContextMode.DATA;
- for (Operation op: mOperations) {
+ mTimeVariables.updateTime(context);
+
+ for (Operation op : mOperations) {
+ if (op instanceof VariableSupport) {
+ ((VariableSupport) op).updateVariables(context);
+ ((VariableSupport) op).registerListening(context);
+ }
op.apply(context);
}
context.mMode = RemoteContext.ContextMode.UNSET;
+
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -375,7 +402,7 @@
* @param minorVersion minor version number, increased when adding new features
* @param patch patch level, increased upon bugfixes
*/
- void setVersion(int majorVersion, int minorVersion, int patch) {
+ void setVersion(int majorVersion, int minorVersion, int patch) {
mVersion = new Version(majorVersion, minorVersion, patch);
}
@@ -389,13 +416,13 @@
* the click coordinates will be the one reported; the order of addition of those click areas
* is therefore meaningful.
*
- * @param id the id of the area, which will be reported on click
+ * @param id the id of the area, which will be reported on click
* @param contentDescription the content description (used for accessibility)
- * @param left the left coordinate of the click area (in pixels)
- * @param top the top coordinate of the click area (in pixels)
- * @param right the right coordinate of the click area (in pixels)
- * @param bottom the bottom coordinate of the click area (in pixels)
- * @param metadata arbitrary metadata associated with the are, also reported on click
+ * @param left the left coordinate of the click area (in pixels)
+ * @param top the top coordinate of the click area (in pixels)
+ * @param right the right coordinate of the click area (in pixels)
+ * @param bottom the bottom coordinate of the click area (in pixels)
+ * @param metadata arbitrary metadata associated with the are, also reported on click
*/
public void addClickArea(int id, String contentDescription,
float left, float top, float right, float bottom, String metadata) {
@@ -417,7 +444,7 @@
* listeners.
*/
public void onClick(float x, float y) {
- for (ClickAreaRepresentation clickArea: mClickAreas) {
+ for (ClickAreaRepresentation clickArea : mClickAreas) {
if (clickArea.contains(x, y)) {
warnClickListeners(clickArea);
}
@@ -430,7 +457,7 @@
* @param id the click area id
*/
public void performClick(int id) {
- for (ClickAreaRepresentation clickArea: mClickAreas) {
+ for (ClickAreaRepresentation clickArea : mClickAreas) {
if (clickArea.mId == id) {
warnClickListeners(clickArea);
}
@@ -441,17 +468,36 @@
* Warn click listeners when a click area is activated
*/
private void warnClickListeners(ClickAreaRepresentation clickArea) {
- for (ClickCallbacks listener: mClickListeners) {
+ for (ClickCallbacks listener : mClickListeners) {
listener.click(clickArea.mId, clickArea.mMetadata);
}
}
- ///////////////////////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ for (Operation op : mOperations) {
+ builder.append(op.toString());
+ builder.append("\n");
+ }
+ return builder.toString();
+ }
+
+ //////////////////////////////////////////////////////////////////////////
// Painting
- ///////////////////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////
private final float[] mScaleOutput = new float[2];
private final float[] mTranslateOutput = new float[2];
+ private int mRepaintNext = -1; // delay to next repaint -1 = don't 1 = asap
+
+ /**
+ * Returns > 0 if it needs to repaint
+ * @return
+ */
+ public int needsRepaint() {
+ return mRepaintNext;
+ }
/**
* Paint the document
@@ -475,6 +521,11 @@
context.mPaintContext.translate(mTranslateOutput[0], mTranslateOutput[1]);
context.mPaintContext.scale(mScaleOutput[0], mScaleOutput[1]);
}
+ mTimeVariables.updateTime(context);
+ context.loadFloat(RemoteContext.ID_WINDOW_WIDTH, getWidth());
+ context.loadFloat(RemoteContext.ID_WINDOW_HEIGHT, getHeight());
+ mRepaintNext = context.updateOps();
+
for (Operation op : mOperations) {
// operations will only be executed if no theme is set (ie UNSPECIFIED)
// or the theme is equal as the one passed in argument to paint.
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
index 54b277a..4b45ab6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
@@ -19,6 +19,7 @@
import com.android.internal.widget.remotecompose.core.operations.ClickArea;
import com.android.internal.widget.remotecompose.core.operations.ClipPath;
import com.android.internal.widget.remotecompose.core.operations.ClipRect;
+import com.android.internal.widget.remotecompose.core.operations.ColorExpression;
import com.android.internal.widget.remotecompose.core.operations.DrawArc;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmap;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmapInt;
@@ -28,9 +29,12 @@
import com.android.internal.widget.remotecompose.core.operations.DrawPath;
import com.android.internal.widget.remotecompose.core.operations.DrawRect;
import com.android.internal.widget.remotecompose.core.operations.DrawRoundRect;
+import com.android.internal.widget.remotecompose.core.operations.DrawText;
+import com.android.internal.widget.remotecompose.core.operations.DrawTextAnchored;
import com.android.internal.widget.remotecompose.core.operations.DrawTextOnPath;
-import com.android.internal.widget.remotecompose.core.operations.DrawTextRun;
import com.android.internal.widget.remotecompose.core.operations.DrawTweenPath;
+import com.android.internal.widget.remotecompose.core.operations.FloatConstant;
+import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
import com.android.internal.widget.remotecompose.core.operations.Header;
import com.android.internal.widget.remotecompose.core.operations.MatrixRestore;
import com.android.internal.widget.remotecompose.core.operations.MatrixRotate;
@@ -42,7 +46,10 @@
import com.android.internal.widget.remotecompose.core.operations.PathData;
import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
import com.android.internal.widget.remotecompose.core.operations.RootContentDescription;
+import com.android.internal.widget.remotecompose.core.operations.ShaderData;
import com.android.internal.widget.remotecompose.core.operations.TextData;
+import com.android.internal.widget.remotecompose.core.operations.TextFromFloat;
+import com.android.internal.widget.remotecompose.core.operations.TextMerge;
import com.android.internal.widget.remotecompose.core.operations.Theme;
import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap;
@@ -67,9 +74,10 @@
public static final int DRAW_BITMAP = 44;
public static final int DRAW_BITMAP_INT = 66;
public static final int DATA_BITMAP = 101;
+ public static final int DATA_SHADER = 45;
public static final int DATA_TEXT = 102;
-/////////////////////////////=====================
+ /////////////////////////////=====================
public static final int CLIP_PATH = 38;
public static final int CLIP_RECT = 39;
public static final int PAINT_VALUES = 40;
@@ -91,6 +99,12 @@
public static final int MATRIX_SAVE = 130;
public static final int MATRIX_RESTORE = 131;
public static final int MATRIX_SET = 132;
+ public static final int DATA_FLOAT = 80;
+ public static final int ANIMATED_FLOAT = 81;
+ public static final int DRAW_TEXT_ANCHOR = 133;
+ public static final int COLOR_EXPRESSIONS = 134;
+ public static final int TEXT_FROM_FLOAT = 135;
+ public static final int TEXT_MERGE = 136;
/////////////////////////////////////////======================
public static IntMap<CompanionOperation> map = new IntMap<>();
@@ -114,7 +128,7 @@
map.put(DRAW_RECT, DrawRect.COMPANION);
map.put(DRAW_ROUND_RECT, DrawRoundRect.COMPANION);
map.put(DRAW_TEXT_ON_PATH, DrawTextOnPath.COMPANION);
- map.put(DRAW_TEXT_RUN, DrawTextRun.COMPANION);
+ map.put(DRAW_TEXT_RUN, DrawText.COMPANION);
map.put(DRAW_TWEEN_PATH, DrawTweenPath.COMPANION);
map.put(DATA_PATH, PathData.COMPANION);
map.put(PAINT_VALUES, PaintData.COMPANION);
@@ -126,6 +140,13 @@
map.put(MATRIX_TRANSLATE, MatrixTranslate.COMPANION);
map.put(CLIP_PATH, ClipPath.COMPANION);
map.put(CLIP_RECT, ClipRect.COMPANION);
+ map.put(DATA_SHADER, ShaderData.COMPANION);
+ map.put(DATA_FLOAT, FloatConstant.COMPANION);
+ map.put(ANIMATED_FLOAT, FloatExpression.COMPANION);
+ map.put(DRAW_TEXT_ANCHOR, DrawTextAnchored.COMPANION);
+ map.put(COLOR_EXPRESSIONS, ColorExpression.COMPANION);
+ map.put(TEXT_FROM_FLOAT, TextFromFloat.COMPANION);
+ map.put(TEXT_MERGE, TextMerge.COMPANION);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
index eece8ad52..ecd0efc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
@@ -68,7 +68,35 @@
public abstract void drawTextOnPath(int textId, int pathId, float hOffset, float vOffset);
- public abstract void drawTextRun(int textID,
+ /**
+ * Return the dimensions (left, top, right, bottom).
+ * Relative to a drawTextRun x=0, y=0;
+ *
+ * @param textId
+ * @param start
+ * @param end if end is -1 it means the whole string
+ * @param monospace measure with better support for monospace
+ * @param bounds the bounds (left, top, right, bottom)
+ */
+ public abstract void getTextBounds(int textId,
+ int start,
+ int end,
+ boolean monospace,
+ float[]bounds);
+
+ /**
+ * Draw a text starting ast x,y
+ *
+ * @param textId reference to the text
+ * @param start
+ * @param end
+ * @param contextStart
+ * @param contextEnd
+ * @param x
+ * @param y
+ * @param rtl
+ */
+ public abstract void drawTextRun(int textId,
int start,
int end,
int contextStart,
@@ -77,6 +105,14 @@
float y,
boolean rtl);
+ /**
+ * Draw an interpolation between two paths
+ * @param path1Id
+ * @param path2Id
+ * @param tween 0.0 = is path1 1.0 is path2
+ * @param start
+ * @param stop
+ */
public abstract void drawTweenPath(int path1Id,
int path2Id,
float tween,
@@ -85,21 +121,70 @@
public abstract void applyPaint(PaintBundle mPaintData);
- public abstract void mtrixScale(float scaleX, float scaleY, float centerX, float centerY);
+ /**
+ * Scale the rendering by scaleX and saleY (1.0 = no scale).
+ * Scaling is done about centerX,centerY.
+ *
+ * @param scaleX
+ * @param scaleY
+ * @param centerX
+ * @param centerY
+ */
+ public abstract void matrixScale(float scaleX, float scaleY, float centerX, float centerY);
+ /**
+ * Translate the rendering
+ * @param translateX
+ * @param translateY
+ */
public abstract void matrixTranslate(float translateX, float translateY);
+ /**
+ * Skew the rendering
+ * @param skewX
+ * @param skewY
+ */
public abstract void matrixSkew(float skewX, float skewY);
+ /**
+ * Rotate the rendering.
+ * Note rotates are cumulative.
+ * @param rotate angle to rotate
+ * @param pivotX x-coordinate about which to rotate
+ * @param pivotY y-coordinate about which to rotate
+ */
public abstract void matrixRotate(float rotate, float pivotX, float pivotY);
+ /**
+ * Save the current state of the transform
+ */
public abstract void matrixSave();
+ /**
+ * Restore the previously saved state of the transform
+ */
public abstract void matrixRestore();
+ /**
+ * Set the clip to a rectangle.
+ * Drawing outside the current clip region will have no effect
+ * @param left
+ * @param top
+ * @param right
+ * @param bottom
+ */
public abstract void clipRect(float left, float top, float right, float bottom);
+ /**
+ * Clip based on a path.
+ * @param pathId
+ * @param regionOp
+ */
public abstract void clipPath(int pathId, int regionOp);
+ /**
+ * Reset the paint
+ */
+ public abstract void reset();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
index c2e8131..52fc314 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
@@ -19,6 +19,7 @@
import com.android.internal.widget.remotecompose.core.operations.ClickArea;
import com.android.internal.widget.remotecompose.core.operations.ClipPath;
import com.android.internal.widget.remotecompose.core.operations.ClipRect;
+import com.android.internal.widget.remotecompose.core.operations.ColorExpression;
import com.android.internal.widget.remotecompose.core.operations.DrawArc;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmap;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmapInt;
@@ -28,9 +29,12 @@
import com.android.internal.widget.remotecompose.core.operations.DrawPath;
import com.android.internal.widget.remotecompose.core.operations.DrawRect;
import com.android.internal.widget.remotecompose.core.operations.DrawRoundRect;
+import com.android.internal.widget.remotecompose.core.operations.DrawText;
+import com.android.internal.widget.remotecompose.core.operations.DrawTextAnchored;
import com.android.internal.widget.remotecompose.core.operations.DrawTextOnPath;
-import com.android.internal.widget.remotecompose.core.operations.DrawTextRun;
import com.android.internal.widget.remotecompose.core.operations.DrawTweenPath;
+import com.android.internal.widget.remotecompose.core.operations.FloatConstant;
+import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
import com.android.internal.widget.remotecompose.core.operations.Header;
import com.android.internal.widget.remotecompose.core.operations.MatrixRestore;
import com.android.internal.widget.remotecompose.core.operations.MatrixRotate;
@@ -43,8 +47,12 @@
import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
import com.android.internal.widget.remotecompose.core.operations.RootContentDescription;
import com.android.internal.widget.remotecompose.core.operations.TextData;
+import com.android.internal.widget.remotecompose.core.operations.TextFromFloat;
+import com.android.internal.widget.remotecompose.core.operations.TextMerge;
import com.android.internal.widget.remotecompose.core.operations.Theme;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
+import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation;
import java.io.File;
import java.io.FileInputStream;
@@ -58,9 +66,20 @@
* Provides an abstract buffer to encode/decode RemoteCompose operations
*/
public class RemoteComposeBuffer {
+ public static final int EASING_CUBIC_STANDARD = FloatAnimation.CUBIC_STANDARD;
+ public static final int EASING_CUBIC_ACCELERATE = FloatAnimation.CUBIC_ACCELERATE;
+ public static final int EASING_CUBIC_DECELERATE = FloatAnimation.CUBIC_DECELERATE;
+ public static final int EASING_CUBIC_LINEAR = FloatAnimation.CUBIC_LINEAR;
+ public static final int EASING_CUBIC_ANTICIPATE = FloatAnimation.CUBIC_ANTICIPATE;
+ public static final int EASING_CUBIC_OVERSHOOT = FloatAnimation.CUBIC_OVERSHOOT;
+ public static final int EASING_CUBIC_CUSTOM = FloatAnimation.CUBIC_CUSTOM;
+ public static final int EASING_SPLINE_CUSTOM = FloatAnimation.SPLINE_CUSTOM;
+ public static final int EASING_EASE_OUT_BOUNCE = FloatAnimation.EASE_OUT_BOUNCE;
+ public static final int EASING_EASE_OUT_ELASTIC = FloatAnimation.EASE_OUT_ELASTIC;
WireBuffer mBuffer = new WireBuffer();
Platform mPlatform = null;
RemoteComposeState mRemoteComposeState;
+ private static final boolean DEBUG = false;
/**
* Provides an abstract buffer to encode/decode RemoteCompose operations
@@ -171,7 +190,7 @@
*
* @param text the string to inject in the buffer
*/
- int addText(String text) {
+ public int addText(String text) {
int id = mRemoteComposeState.dataGetId(text);
if (id == -1) {
id = mRemoteComposeState.cache(text);
@@ -350,7 +369,6 @@
addDrawPath(id);
}
-
/**
* Draw the specified path
*
@@ -426,12 +444,160 @@
float y,
boolean rtl) {
int textId = addText(text);
- DrawTextRun.COMPANION.apply(
+ DrawText.COMPANION.apply(
mBuffer, textId, start, end,
contextStart, contextEnd, x, y, rtl);
}
/**
+ * Draw the text, with origin at (x,y). The origin is interpreted
+ * based on the Align setting in the paint.
+ *
+ * @param textId The text to be drawn
+ * @param start The index of the first character in text to draw
+ * @param end (end - 1) is the index of the last character in text to draw
+ * @param contextStart
+ * @param contextEnd
+ * @param x The x-coordinate of the origin of the text being drawn
+ * @param y The y-coordinate of the baseline of the text being drawn
+ * @param rtl Draw RTTL
+ */
+ public void addDrawTextRun(int textId,
+ int start,
+ int end,
+ int contextStart,
+ int contextEnd,
+ float x,
+ float y,
+ boolean rtl) {
+ DrawText.COMPANION.apply(
+ mBuffer, textId, start, end,
+ contextStart, contextEnd, x, y, rtl);
+ }
+
+ /**
+ * Draw a text on canvas at relative to position (x, y),
+ * offset panX and panY.
+ * <br>
+ * The panning factors (panX, panY) mapped to the
+ * resulting bounding box of the text, in such a way that a
+ * panning factor of (0.0, 0.0) would center the text at (x, y)
+ * <ul>
+ * <li> Panning of -1.0, -1.0 - the text above & right of x,y.</li>
+ * <li>Panning of 1.0, 1.0 - the text is below and to the left</li>
+ * <li>Panning of 1.0, 0.0 - the test is centered & to the right of x,y</li>
+ * </ul>
+ * Setting panY to NaN results in y being the baseline of the text.
+ *
+ * @param text text to draw
+ * @param x Coordinate of the Anchor
+ * @param y Coordinate of the Anchor
+ * @param panX justifies text -1.0=right, 0.0=center, 1.0=left
+ * @param panY position text -1.0=above, 0.0=center, 1.0=below, Nan=baseline
+ * @param flags 1 = RTL
+ */
+ public void drawTextAnchored(String text,
+ float x,
+ float y,
+ float panX,
+ float panY,
+ int flags) {
+ int textId = addText(text);
+ DrawTextAnchored.COMPANION.apply(
+ mBuffer, textId,
+ x, y,
+ panX, panY,
+ flags);
+ }
+
+ /**
+ * Add a text and id so that it can be used
+ *
+ * @param text
+ * @return
+ */
+ public int createTextId(String text) {
+ return addText(text);
+ }
+
+ /**
+ * Merge two text (from id's) output one id
+ * @param id1 left id
+ * @param id2 right id
+ * @return new id that merges the two text
+ */
+ public int textMerge(int id1, int id2) {
+ int textId = addText(id1 + "+" + id2);
+ TextMerge.COMPANION.apply(mBuffer, textId, id1, id2);
+ return textId;
+ }
+
+ public static final int PAD_AFTER_SPACE = TextFromFloat.PAD_AFTER_SPACE;
+ public static final int PAD_AFTER_NONE = TextFromFloat.PAD_AFTER_NONE;
+ public static final int PAD_AFTER_ZERO = TextFromFloat.PAD_AFTER_ZERO;
+ public static final int PAD_PRE_SPACE = TextFromFloat.PAD_PRE_SPACE;
+ public static final int PAD_PRE_NONE = TextFromFloat.PAD_PRE_NONE;
+ public static final int PAD_PRE_ZERO = TextFromFloat.PAD_PRE_ZERO;
+
+ /**
+ * Create a TextFromFloat command which creates text from a Float.
+ *
+ * @param value The value to convert
+ * @param digitsBefore the digits before the decimal point
+ * @param digitsAfter the digits after the decimal point
+ * @param flags configure the behaviour using PAD_PRE_* and PAD_AFTER* flags
+ * @return id of the string that can be passed to drawTextAnchored
+ */
+ public int createTextFromFloat(float value, short digitsBefore,
+ short digitsAfter, int flags) {
+ String placeHolder = Utils.floatToString(value)
+ + "(" + digitsBefore + "," + digitsAfter + "," + flags + ")";
+ int id = mRemoteComposeState.dataGetId(placeHolder);
+ if (id == -1) {
+ id = mRemoteComposeState.cache(placeHolder);
+ // TextData.COMPANION.apply(mBuffer, id, text);
+ }
+ TextFromFloat.COMPANION.apply(mBuffer, id, value, digitsBefore,
+ digitsAfter, flags);
+ return id;
+ }
+
+ /**
+ * Draw a text on canvas at relative to position (x, y),
+ * offset panX and panY.
+ * <br>
+ * The panning factors (panX, panY) mapped to the
+ * resulting bounding box of the text, in such a way that a
+ * panning factor of (0.0, 0.0) would center the text at (x, y)
+ * <ul>
+ * <li> Panning of -1.0, -1.0 - the text above & right of x,y.</li>
+ * <li>Panning of 1.0, 1.0 - the text is below and to the left</li>
+ * <li>Panning of 1.0, 0.0 - the test is centered & to the right of x,y</li>
+ * </ul>
+ * Setting panY to NaN results in y being the baseline of the text.
+ *
+ * @param textId text to draw
+ * @param x Coordinate of the Anchor
+ * @param y Coordinate of the Anchor
+ * @param panX justifies text -1.0=right, 0.0=center, 1.0=left
+ * @param panY position text -1.0=above, 0.0=center, 1.0=below, Nan=baseline
+ * @param flags 1 = RTL
+ */
+ public void drawTextAnchored(int textId,
+ float x,
+ float y,
+ float panX,
+ float panY,
+ int flags) {
+
+ DrawTextAnchored.COMPANION.apply(
+ mBuffer, textId,
+ x, y,
+ panX, panY,
+ flags);
+ }
+
+ /**
* draw an interpolation between two paths that have the same pattern
* <p>
* Warning paths objects are not immutable and this is not taken into consideration
@@ -490,6 +656,10 @@
return id;
}
+ /**
+ * Adds a paint Bundle to the doc
+ * @param paint
+ */
public void addPaint(PaintBundle paint) {
PaintData.COMPANION.apply(mBuffer, paint);
}
@@ -499,7 +669,9 @@
mBuffer.setIndex(0);
while (mBuffer.available()) {
int opId = mBuffer.readByte();
- System.out.println(">>> " + opId);
+ if (DEBUG) {
+ Utils.log(">> " + opId);
+ }
CompanionOperation operation = Operations.map.get(opId);
if (operation == null) {
throw new RuntimeException("Unknown operation encountered " + opId);
@@ -519,7 +691,6 @@
Theme.COMPANION.apply(mBuffer, theme);
}
-
static String version() {
return "v1.0";
}
@@ -654,8 +825,8 @@
/**
* Add a pre-concat of the current matrix with the specified scale.
*
- * @param scaleX The amount to scale in X
- * @param scaleY The amount to scale in Y
+ * @param scaleX The amount to scale in X
+ * @param scaleY The amount to scale in Y
*/
public void addMatrixScale(float scaleX, float scaleY) {
MatrixScale.COMPANION.apply(mBuffer, scaleX, scaleY, Float.NaN, Float.NaN);
@@ -673,12 +844,174 @@
MatrixScale.COMPANION.apply(mBuffer, scaleX, scaleY, centerX, centerY);
}
+ /**
+ * sets the clip based on clip id
+ * @param pathId 0 clears the clip
+ */
public void addClipPath(int pathId) {
ClipPath.COMPANION.apply(mBuffer, pathId);
}
+ /**
+ * Sets the clip based on clip rec
+ * @param left
+ * @param top
+ * @param right
+ * @param bottom
+ */
public void addClipRect(float left, float top, float right, float bottom) {
ClipRect.COMPANION.apply(mBuffer, left, top, right, bottom);
}
+
+ /**
+ * Add a float return a NaN number pointing to that float
+ * @param value
+ * @return
+ */
+ public float addFloat(float value) {
+ int id = mRemoteComposeState.cacheFloat(value);
+ FloatConstant.COMPANION.apply(mBuffer, id, value);
+ return Utils.asNan(id);
+ }
+
+ /**
+ * Add a float that is a computation based on variables
+ * @param value A RPN style float operation i.e. "4, 3, ADD" outputs 7
+ * @return NaN id of the result of the calculation
+ */
+ public float addAnimatedFloat(float... value) {
+ int id = mRemoteComposeState.cache(value);
+ FloatExpression.COMPANION.apply(mBuffer, id, value, null);
+ return Utils.asNan(id);
+ }
+
+ /**
+ * Add a float that is a computation based on variables.
+ * see packAnimation
+ * @param value A RPN style float operation i.e. "4, 3, ADD" outputs 7
+ * @param animation Array of floats that represents animation
+ * @return NaN id of the result of the calculation
+ */
+ public float addAnimatedFloat(float[] value, float[] animation) {
+ int id = mRemoteComposeState.cache(value);
+ FloatExpression.COMPANION.apply(mBuffer, id, value, animation);
+ return Utils.asNan(id);
+ }
+
+ /**
+ * Add a color that represents the tween between two colors
+ * @param color1
+ * @param color2
+ * @param tween
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(int color1, int color2, float tween) {
+ ColorExpression c = new ColorExpression(0, 0, color1, color2, tween);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * Add a color that represents the tween between two colors where color1
+ * is the id of a color
+ * @param color1
+ * @param color2
+ * @param tween
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(short color1, int color2, float tween) {
+ ColorExpression c = new ColorExpression(0, 1, color1, color2, tween);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * Add a color that represents the tween between two colors where color2
+ * is the id of a color
+ * @param color1
+ * @param color2
+ * @param tween
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(int color1, short color2, float tween) {
+ ColorExpression c = new ColorExpression(0, 2, color1, color2, tween);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * Add a color that represents the tween between two colors where color1 &
+ * color2 are the ids of colors
+ * @param color1
+ * @param color2
+ * @param tween
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(short color1, short color2, float tween) {
+ ColorExpression c = new ColorExpression(0, 3, color1, color2, tween);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * Color calculated by Hue saturation and value.
+ * (as floats they can be variables used to create color transitions)
+ * @param hue
+ * @param sat
+ * @param value
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(float hue, float sat, float value) {
+ ColorExpression c = new ColorExpression(0, hue, sat, value);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * Color calculated by Alpha, Hue saturation and value.
+ * (as floats they can be variables used to create color transitions)
+ * @param alpha
+ * @param hue
+ * @param sat
+ * @param value
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(int alpha, float hue, float sat, float value) {
+ ColorExpression c = new ColorExpression(0, alpha, hue, sat, value);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * create and animation based on description and return as an array of
+ * floats. see addAnimatedFloat
+ * @param duration
+ * @param type
+ * @param spec
+ * @param initialValue
+ * @param wrap
+ * @return
+ */
+ public static float[] packAnimation(float duration,
+ int type,
+ float[] spec,
+ float initialValue,
+ float wrap) {
+
+ return FloatAnimation.packToFloatArray(duration, type, spec, initialValue, wrap);
+ }
+
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
index 17e8c83..66a37e67 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
@@ -15,26 +15,53 @@
*/
package com.android.internal.widget.remotecompose.core;
+import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_CONTINUOUS_SEC;
+import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_TIME_IN_MIN;
+import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_TIME_IN_SEC;
+import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_WINDOW_HEIGHT;
+import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_WINDOW_WIDTH;
+
import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap;
+import java.util.ArrayList;
import java.util.HashMap;
/**
* Represents runtime state for a RemoteCompose document
+ * State includes things like the value of variables
*/
public class RemoteComposeState {
-
+ public static final int START_ID = 42;
+ private static final int MAX_FLOATS = 500;
private final IntMap<Object> mIntDataMap = new IntMap<>();
private final IntMap<Boolean> mIntWrittenMap = new IntMap<>();
private final HashMap<Object, Integer> mDataIntMap = new HashMap();
+ private final float[] mFloatMap = new float[MAX_FLOATS]; // efficient cache
+ private final int[] mColorMap = new int[MAX_FLOATS]; // efficient cache
+ private int mNextId = START_ID;
- private static int sNextId = 42;
+ {
+ for (int i = 0; i < mFloatMap.length; i++) {
+ mFloatMap[i] = Float.NaN;
+ }
+ }
- public Object getFromId(int id) {
+ /**
+ * Get Object based on id. The system will cache things like bitmaps
+ * Paths etc. They can be accessed with this command
+ * @param id
+ * @return
+ */
+ public Object getFromId(int id) {
return mIntDataMap.get(id);
}
- public boolean containsId(int id) {
+ /**
+ * true if the cache contain this id
+ * @param id
+ * @return
+ */
+ public boolean containsId(int id) {
return mIntDataMap.get(id) != null;
}
@@ -69,6 +96,65 @@
}
/**
+ * Insert an item in the cache
+ */
+ public void update(int id, Object item) {
+ mDataIntMap.remove(mIntDataMap.get(id));
+ mDataIntMap.put(item, id);
+ mIntDataMap.put(id, item);
+ }
+
+ /**
+ * Insert an item in the cache
+ */
+ public int cacheFloat(float item) {
+ int id = nextId();
+ mFloatMap[id] = item;
+ return id;
+ }
+
+ /**
+ * Insert an item in the cache
+ */
+ public void cacheFloat(int id, float item) {
+ mFloatMap[id] = item;
+ }
+
+ /**
+ * Insert an item in the cache
+ */
+ public void updateFloat(int id, float item) {
+ mFloatMap[id] = item;
+ }
+
+ /**
+ * get float
+ */
+ public float getFloat(int id) {
+ return mFloatMap[id];
+ }
+
+ /**
+ * Get the float value
+ *
+ * @param id
+ * @return
+ */
+ public int getColor(int id) {
+ return mColorMap[id];
+ }
+
+ /**
+ * Modify the color at id.
+ * @param id
+ * @param color
+ */
+ public void updateColor(int id, int color) {
+ mColorMap[id] = color;
+ }
+
+
+ /**
* Method to determine if a cached value has been written to the documents WireBuffer based on
* its id.
*/
@@ -79,22 +165,90 @@
/**
* Method to mark that a value, represented by its id, has been written to the WireBuffer
*/
- public void markWritten(int id) {
+ public void markWritten(int id) {
mIntWrittenMap.put(id, true);
}
/**
- * Clear the record of the values that have been written to the WireBuffer.
+ * Clear the record of the values that have been written to the WireBuffer.
*/
void reset() {
mIntWrittenMap.clear();
}
- public static int nextId() {
- return sNextId++;
+ /**
+ * Get the next available id
+ * @return
+ */
+ public int nextId() {
+ return mNextId++;
}
- public static void setNextId(int id) {
- sNextId = id;
+
+ /**
+ * Set the next id
+ * @param id
+ */
+ public void setNextId(int id) {
+ mNextId = id;
+ }
+
+ IntMap<ArrayList<VariableSupport>> mVarListeners = new IntMap<>();
+ ArrayList<VariableSupport> mAllVarListeners = new ArrayList<>();
+
+ private void add(int id, VariableSupport variableSupport) {
+ ArrayList<VariableSupport> v = mVarListeners.get(id);
+ if (v == null) {
+ v = new ArrayList<VariableSupport>();
+ mVarListeners.put(id, v);
+ }
+ v.add(variableSupport);
+ mAllVarListeners.add(variableSupport);
+ }
+
+ /**
+ * Commands that listen to variables add themselves.
+ * @param id
+ * @param variableSupport
+ */
+ public void listenToVar(int id, VariableSupport variableSupport) {
+ add(id, variableSupport);
+ }
+
+ /**
+ * List of Commands that need to be updated
+ * @param context
+ * @return
+ */
+ public int getOpsToUpdate(RemoteContext context) {
+ for (VariableSupport vs : mAllVarListeners) {
+ vs.updateVariables(context);
+ }
+ if (mVarListeners.get(ID_CONTINUOUS_SEC) != null) {
+ return 1;
+ }
+ if (mVarListeners.get(ID_TIME_IN_SEC) != null) {
+ return 1000;
+ }
+ if (mVarListeners.get(ID_TIME_IN_MIN) != null) {
+ return 1000 * 60;
+ }
+ return -1;
+ }
+
+ /**
+ * Set the width of the overall document on screen.
+ * @param width
+ */
+ public void setWindowWidth(float width) {
+ updateFloat(ID_WINDOW_WIDTH, width);
+ }
+
+ /**
+ * Set the width of the overall document on screen.
+ * @param height
+ */
+ public void setWindowHeight(float height) {
+ updateFloat(ID_WINDOW_HEIGHT, height);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
index d16cbc5..7e72168 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,10 @@
*/
package com.android.internal.widget.remotecompose.core;
+import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
+import com.android.internal.widget.remotecompose.core.operations.ShaderData;
import com.android.internal.widget.remotecompose.core.operations.Theme;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
/**
* Specify an abstract context used to playback RemoteCompose documents
@@ -27,7 +30,7 @@
public abstract class RemoteContext {
protected CoreDocument mDocument;
public RemoteComposeState mRemoteComposeState;
-
+ long mStart = System.nanoTime(); // todo This should be set at a hi level
protected PaintContext mPaintContext = null;
ContextMode mMode = ContextMode.UNSET;
@@ -37,9 +40,40 @@
public float mWidth = 0f;
public float mHeight = 0f;
+ /**
+ * Load a path under an id.
+ * Paths can be use in clip drawPath and drawTweenPath
+ * @param instanceId
+ * @param floatPath
+ */
public abstract void loadPathData(int instanceId, float[] floatPath);
/**
+ * Associate a name with a give id.
+ *
+ * @param varName
+ * @param varId
+ * @param varType
+ */
+ public abstract void loadVariableName(String varName, int varId, int varType);
+
+ /**
+ * Save a color under a given id
+ * @param id
+ * @param color
+ */
+ public abstract void loadColor(int id, int color);
+
+ /**
+ * gets the time animation clock as float in seconds
+ * @return a monotonic time in seconds (arbitrary zero point)
+ */
+ public float getAnimationTime() {
+ return (System.nanoTime() - mStart) * 1E-9f;
+ }
+
+
+ /**
* The context can be used in a few different mode, allowing operations to skip being executed:
* - UNSET : all operations will get executed
* - DATA : only operations dealing with DATA (eg loading a bitmap) should execute
@@ -96,6 +130,8 @@
public void header(int majorVersion, int minorVersion, int patchVersion,
int width, int height, long capabilities
) {
+ mRemoteComposeState.setWindowWidth(width);
+ mRemoteComposeState.setWindowHeight(height);
mDocument.setVersion(majorVersion, minorVersion, patchVersion);
mDocument.setWidth(width);
mDocument.setHeight(height);
@@ -137,9 +173,105 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// Data handling
///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Save a bitmap under an imageId
+ * @param imageId
+ * @param width
+ * @param height
+ * @param bitmap
+ */
public abstract void loadBitmap(int imageId, int width, int height, byte[] bitmap);
+
+ /**
+ * Save a string under a given id
+ * @param id
+ * @param text
+ */
public abstract void loadText(int id, String text);
+ /**
+ * Get a string given an id
+ * @param id
+ * @return
+ */
+ public abstract String getText(int id);
+
+ /**
+ * Load a float
+ * @param id
+ * @param value
+ */
+ public abstract void loadFloat(int id, float value);
+
+ /**
+ * Load an animated float associated with an id
+ * Todo: Remove?
+ * @param id
+ * @param animatedFloat
+ */
+ public abstract void loadAnimatedFloat(int id, FloatExpression animatedFloat);
+
+ /**
+ * Save a shader under and ID
+ * @param id
+ * @param value
+ */
+ public abstract void loadShader(int id, ShaderData value);
+
+ /**
+ * Get a float given an id
+ * @param id
+ * @return
+ */
+ public abstract float getFloat(int id);
+
+ /**
+ * Get the color given and ID
+ * @param id
+ * @return
+ */
+ public abstract int getColor(int id);
+
+ /**
+ * called to notify system that a command is interested in a variable
+ * @param id
+ * @param variableSupport
+ */
+ public abstract void listensTo(int id, VariableSupport variableSupport);
+
+ /**
+ * Notify commands with variables have changed
+ * @return
+ */
+ public abstract int updateOps();
+
+ /**
+ * Get a shader given the id
+ * @param id
+ * @return
+ */
+ public abstract ShaderData getShader(int id);
+
+ public static final int ID_CONTINUOUS_SEC = 1;
+ public static final int ID_TIME_IN_SEC = 2;
+ public static final int ID_TIME_IN_MIN = 3;
+ public static final int ID_TIME_IN_HR = 4;
+ public static final int ID_WINDOW_WIDTH = 5;
+ public static final int ID_WINDOW_HEIGHT = 6;
+ public static final int ID_COMPONENT_WIDTH = 7;
+ public static final int ID_COMPONENT_HEIGHT = 8;
+ public static final int ID_CALENDAR_MONTH = 9;
+
+ public static final float FLOAT_CONTINUOUS_SEC = Utils.asNan(ID_CONTINUOUS_SEC);
+ public static final float FLOAT_TIME_IN_SEC = Utils.asNan(ID_TIME_IN_SEC);
+ public static final float FLOAT_TIME_IN_MIN = Utils.asNan(ID_TIME_IN_MIN);
+ public static final float FLOAT_TIME_IN_HR = Utils.asNan(ID_TIME_IN_HR);
+ public static final float FLOAT_CALENDAR_MONTH = Utils.asNan(ID_CALENDAR_MONTH);
+ public static final float FLOAT_WINDOW_WIDTH = Utils.asNan(ID_WINDOW_WIDTH);
+ public static final float FLOAT_WINDOW_HEIGHT = Utils.asNan(ID_WINDOW_HEIGHT);
+ public static final float FLOAT_COMPONENT_WIDTH = Utils.asNan(ID_COMPONENT_WIDTH);
+ public static final float FLOAT_COMPONENT_HEIGHT = Utils.asNan(ID_COMPONENT_HEIGHT);
///////////////////////////////////////////////////////////////////////////////////////////////
// Click handling
///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
new file mode 100644
index 0000000..e9708b7
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
@@ -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.internal.widget.remotecompose.core;
+
+import java.time.LocalDateTime;
+
+/**
+ * This generates the standard system variables for time.
+ */
+public class TimeVariables {
+ /**
+ * This class populates all time variables in the system
+ * @param context
+ */
+ public void updateTime(RemoteContext context) {
+ LocalDateTime dateTime = LocalDateTime.now();
+ // This define the time in the format
+ // seconds run from Midnight=0 quantized to seconds hour 0..3599
+ // minutes run from Midnight=0 quantized to minutes 0..1439
+ // hours run from Midnight=0 quantized to Hours 0-23
+ // CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600
+ // CONTINUOUS_SEC is accurate to milliseconds due to float precession
+ int month = dateTime.getDayOfMonth();
+ int hour = dateTime.getHour();
+ int minute = dateTime.getMinute();
+ int seconds = dateTime.getSecond();
+ int currentMinute = hour * 60 + minute;
+ int currentSeconds = minute * 60 + seconds;
+ float sec = currentSeconds + dateTime.getNano() * 1E-9f;
+
+ context.loadFloat(RemoteContext.ID_CONTINUOUS_SEC, sec);
+ context.loadFloat(RemoteContext.ID_TIME_IN_SEC, currentSeconds);
+ context.loadFloat(RemoteContext.ID_TIME_IN_MIN, currentMinute);
+ context.loadFloat(RemoteContext.ID_TIME_IN_HR, hour);
+ context.loadFloat(RemoteContext.ID_CALENDAR_MONTH, month);
+
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
new file mode 100644
index 0000000..d59b1bc
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core;
+
+/**
+ * Interface for operators that interact with variables
+ * Threw this they register to listen to particular variables
+ * and are notified when they change
+ */
+public interface VariableSupport {
+ /**
+ * Call to allow an operator to register interest in variables.
+ * Typically they call context.listensTo(id, this)
+ * @param context
+ */
+ void registerListening(RemoteContext context);
+
+ /**
+ * Called to be notified that the variables you are interested have changed.
+ * @param context
+ */
+ void updateVariables(RemoteContext context);
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
index 76b7144..f186322 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
@@ -51,11 +51,12 @@
@Override
public String toString() {
- return "BITMAP DATA $imageId";
+ return "BITMAP DATA " + mImageId;
}
public static class Companion implements CompanionOperation {
- private Companion() {}
+ private Companion() {
+ }
@Override
public String name() {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
index 8d4a787..e6d5fe7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
@@ -24,6 +24,11 @@
import java.util.List;
+/**
+ * Defines a path that clips a the subsequent drawing commands
+ * Use MatrixSave and MatrixRestore commands to remove clip
+ * TODO allow id 0 to mean null?
+ */
public class ClipPath extends PaintOperation {
public static final Companion COMPANION = new Companion();
int mId;
@@ -93,5 +98,4 @@
public void paint(PaintContext context) {
context.clipPath(mId, mRegionOp);
}
-}
-
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
index 803618a..613eceb 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
@@ -15,88 +15,36 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class ClipRect extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mLeft;
- float mTop;
- float mRight;
- float mBottom;
+/**
+ * Support clip with a rectangle
+ */
+public class ClipRect extends DrawBase4 {
+ public static final Companion COMPANION =
+ new Companion(Operations.CLIP_RECT) {
+ @Override
+ public Operation construct(float x1,
+ float y1,
+ float x2,
+ float y2) {
+ return new ClipRect(x1, y1, x2, y2);
+ }
+ };
public ClipRect(
float left,
float top,
float right,
float bottom) {
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
-
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom);
- }
-
- @Override
- public String toString() {
- return "ClipRect " + mLeft + " " + mTop
- + " " + mRight + " " + mBottom + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sLeft = buffer.readFloat();
- float srcTop = buffer.readFloat();
- float srcRight = buffer.readFloat();
- float srcBottom = buffer.readFloat();
-
- ClipRect op = new ClipRect(sLeft, srcTop, srcRight, srcBottom);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "ClipRect";
- }
-
- @Override
- public int id() {
- return Operations.CLIP_RECT;
- }
-
- public void apply(WireBuffer buffer,
- float left,
- float top,
- float right,
- float bottom) {
- buffer.start(Operations.CLIP_RECT);
- buffer.writeFloat(left);
- buffer.writeFloat(top);
- buffer.writeFloat(right);
- buffer.writeFloat(bottom);
- }
+ super(left, top, right, bottom);
+ mName = "ClipRect";
}
@Override
public void paint(PaintContext context) {
- context.clipRect(mLeft,
- mTop,
- mRight,
- mBottom);
+ context.clipRect(mX1, mY1, mX2, mY2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
new file mode 100644
index 0000000..7d28cea
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Operation to Colors
+ * Color modes
+ * mMode = 0 two colors and a tween
+ * mMode = 1 color1 is a colorID.
+ * mMode = 2 color2 is a colorID.
+ * mMode = 3 color1 & color2 are ids
+ * mMode = 4 H S V mode
+ */
+public class ColorExpression implements Operation, VariableSupport {
+ public int mId;
+ int mMode;
+ public int mColor1;
+ public int mColor2;
+ public float mTween = 0.0f;
+
+
+ public float mHue = 0; // only in Mode 4
+ public float mSat = 0;
+ public float mValue = 0;
+ public float mOutHue = 0; // only in Mode 4
+ public float mOutSat = 0;
+ public float mOutValue = 0;
+ public int mAlpha = 0xFF; // only used in hsv mode
+
+ public float mOutTween = 0.0f;
+ public int mOutColor1;
+ public int mOutColor2;
+ public static final Companion COMPANION = new Companion();
+ public static final int HSV_MODE = 4;
+ public ColorExpression(int id, float hue, float sat, float value) {
+ mMode = HSV_MODE;
+ mAlpha = 0xFF;
+ mOutHue = mHue = hue;
+ mOutSat = mSat = sat;
+ mOutValue = mValue = value;
+ mColor1 = Float.floatToRawIntBits(hue);
+ mColor2 = Float.floatToRawIntBits(sat);
+ mTween = value;
+ }
+ public ColorExpression(int id, int alpha, float hue, float sat, float value) {
+ mMode = HSV_MODE;
+ mAlpha = alpha;
+ mOutHue = mHue = hue;
+ mOutSat = mSat = sat;
+ mOutValue = mValue = value;
+ mColor1 = Float.floatToRawIntBits(hue);
+ mColor2 = Float.floatToRawIntBits(sat);
+ mTween = value;
+ }
+
+ public ColorExpression(int id, int mode, int color1, int color2, float tween) {
+ this.mId = id;
+ this.mMode = mode & 0xFF;
+ this.mAlpha = (mode >> 16) & 0xFF;
+ if (mMode == HSV_MODE) {
+ mOutHue = mHue = Float.intBitsToFloat(color1);
+ mOutSat = mSat = Float.intBitsToFloat(color2);
+ mOutValue = mValue = tween;
+ }
+ this.mColor1 = color1;
+ this.mColor2 = color2;
+ this.mTween = tween;
+ this.mOutTween = tween;
+ this.mOutColor1 = color1;
+ this.mOutColor2 = color2;
+
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ if (mMode == 4) {
+ if (Float.isNaN(mHue)) {
+ mOutHue = context.getFloat(Utils.idFromNan(mHue));
+ }
+ if (Float.isNaN(mSat)) {
+ mOutSat = context.getFloat(Utils.idFromNan(mSat));
+ }
+ if (Float.isNaN(mValue)) {
+ mOutValue = context.getFloat(Utils.idFromNan(mValue));
+ }
+ }
+ if (Float.isNaN(mTween)) {
+ mOutTween = context.getFloat(Utils.idFromNan(mTween));
+ }
+ if ((mMode & 1) == 1) {
+ mOutColor1 = context.getColor(mColor1);
+ }
+ if ((mMode & 2) == 2) {
+ mOutColor2 = context.getColor(mColor2);
+ }
+ }
+
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (mMode == 4) {
+ if (Float.isNaN(mHue)) {
+ context.listensTo(Utils.idFromNan(mHue), this);
+ }
+ if (Float.isNaN(mSat)) {
+ context.listensTo(Utils.idFromNan(mSat), this);
+ }
+ if (Float.isNaN(mValue)) {
+ context.listensTo(Utils.idFromNan(mValue), this);
+ }
+ return;
+ }
+ if (Float.isNaN(mTween)) {
+ context.listensTo(Utils.idFromNan(mTween), this);
+ }
+ if ((mMode & 1) == 1) {
+ context.listensTo(mColor1, this);
+ }
+ if ((mMode & 2) == 2) {
+ context.listensTo(mColor2, this);
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ if (mMode == 4) {
+ context.loadColor(mId, (mAlpha << 24)
+ | (0xFFFFFF & Utils.hsvToRgb(mOutHue, mOutSat, mOutValue)));
+ return;
+ }
+ if (mOutTween == 0.0) {
+ context.loadColor(mId, mColor1);
+ } else {
+ if ((mMode & 1) == 1) {
+ mOutColor1 = context.getColor(mColor1);
+ }
+ if ((mMode & 2) == 2) {
+ mOutColor2 = context.getColor(mColor2);
+ }
+
+ context.loadColor(mId,
+ Utils.interpolateColor(mOutColor1, mOutColor2, mOutTween));
+ }
+
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ int mode = mMode | (mAlpha << 16);
+ COMPANION.apply(buffer, mId, mode, mColor1, mColor2, mTween);
+ }
+
+ @Override
+ public String toString() {
+ if (mMode == 4) {
+ return "ColorExpression[" + mId + "] = hsv (" + Utils.floatToString(mHue)
+ + ", " + Utils.floatToString(mSat)
+ + ", " + Utils.floatToString(mValue) + ")";
+ }
+
+ String c1 = (mMode & 1) == 1 ? "[" + mColor1 + "]" : Utils.colorInt(mColor1);
+ String c2 = (mMode & 2) == 2 ? "[" + mColor2 + "]" : Utils.colorInt(mColor2);
+ return "ColorExpression[" + mId + "] = tween(" + c1
+ + ", " + c2 + ", "
+ + Utils.floatToString(mTween) + ")";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "ColorExpression";
+ }
+
+ @Override
+ public int id() {
+ return Operations.COLOR_EXPRESSIONS;
+ }
+
+ /**
+ * Call to write a ColorExpression object on the buffer
+ * @param buffer
+ * @param id of the ColorExpression object
+ * @param mode if colors are id or actual values
+ * @param color1
+ * @param color2
+ * @param tween
+ */
+ public void apply(WireBuffer buffer,
+ int id, int mode,
+ int color1, int color2, float tween) {
+ buffer.start(Operations.COLOR_EXPRESSIONS);
+ buffer.writeInt(id);
+ buffer.writeInt(mode);
+ buffer.writeInt(color1);
+ buffer.writeInt(color2);
+ buffer.writeFloat(tween);
+
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int id = buffer.readInt();
+ int mode = buffer.readInt();
+ int color1 = buffer.readInt();
+ int color2 = buffer.readInt();
+ float tween = buffer.readFloat();
+
+ operations.add(new ColorExpression(id, mode, color1, color2, tween));
+ }
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
index e829975..c176864 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
@@ -15,107 +15,36 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
+public class DrawArc extends DrawBase6 {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_ARC) {
+ @Override
+ public Operation construct(float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ return new DrawArc(v1, v2, v3, v4, v5, v6);
+ }
+ };
-public class DrawArc extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mLeft;
- float mTop;
- float mRight;
- float mBottom;
- float mStartAngle;
- float mSweepAngle;
-
- public DrawArc(
- float left,
- float top,
- float right,
- float bottom,
- float startAngle,
- float sweepAngle) {
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
- mStartAngle = startAngle;
- mSweepAngle = sweepAngle;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mLeft,
- mTop,
- mRight,
- mBottom,
- mStartAngle,
- mSweepAngle);
- }
-
- @Override
- public String toString() {
- return "DrawArc " + mLeft + " " + mTop
- + " " + mRight + " " + mBottom + " "
- + "- " + mStartAngle + " " + mSweepAngle + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sLeft = buffer.readFloat();
- float srcTop = buffer.readFloat();
- float srcRight = buffer.readFloat();
- float srcBottom = buffer.readFloat();
- float mStartAngle = buffer.readFloat();
- float mSweepAngle = buffer.readFloat();
- DrawArc op = new DrawArc(sLeft, srcTop, srcRight, srcBottom,
- mStartAngle, mSweepAngle);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "DrawArc";
- }
-
- @Override
- public int id() {
- return Operations.DRAW_ARC;
- }
-
- public void apply(WireBuffer buffer,
- float left,
- float top,
- float right,
- float bottom,
- float startAngle,
- float sweepAngle) {
- buffer.start(Operations.DRAW_ARC);
- buffer.writeFloat(left);
- buffer.writeFloat(top);
- buffer.writeFloat(right);
- buffer.writeFloat(bottom);
- buffer.writeFloat(startAngle);
- buffer.writeFloat(sweepAngle);
- }
+ public DrawArc(float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ super(v1, v2, v3, v4, v5, v6);
+ mName = "DrawArc";
}
@Override
public void paint(PaintContext context) {
- context.drawArc(mLeft,
- mTop,
- mRight,
- mBottom,
- mStartAngle,
- mSweepAngle);
+ context.drawArc(mV1, mV2, mV3, mV4, mV5, mV6);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
new file mode 100644
index 0000000..0963c13
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Base class for commands that take 3 float
+ */
+public abstract class DrawBase2 extends PaintOperation
+ implements VariableSupport {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_CIRCLE) {
+ @Override
+ public Operation construct(float x1, float y1) {
+ // subclass should return new DrawX(x1, y1);
+ return null;
+ }
+ };
+ protected String mName = "DrawRectBase";
+ float mV1;
+ float mV2;
+ float mValue1;
+ float mValue2;
+
+ public DrawBase2(float v1, float v2) {
+ mValue1 = v1;
+ mValue2 = v2;
+ mV1 = v1;
+ mV2 = v2;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ mV1 = (Float.isNaN(mValue1))
+ ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1;
+ mV2 = (Float.isNaN(mValue2))
+ ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mValue1)) {
+ context.listensTo(Utils.idFromNan(mValue1), this);
+ }
+ if (Float.isNaN(mValue2)) {
+ context.listensTo(Utils.idFromNan(mValue2), this);
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mV1, mV2);
+ }
+
+ @Override
+ public String toString() {
+ return mName + " " + floatToString(mV1) + " " + floatToString(mV2);
+ }
+
+ public static class Companion implements CompanionOperation {
+ public final int OP_CODE;
+
+ protected Companion(int code) {
+ OP_CODE = code;
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float v1 = buffer.readFloat();
+ float v2 = buffer.readFloat();
+
+ Operation op = construct(v1, v2);
+ operations.add(op);
+ }
+
+ /**
+ * Override to construct a 2 float value operation
+ * @param x1
+ * @param y1
+ * @return
+ */
+ public Operation construct(float x1, float y1) {
+ return null;
+ }
+
+ @Override
+ public String name() {
+ return "DrawRect";
+ }
+
+ @Override
+ public int id() {
+ return OP_CODE;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param x1
+ * @param y1
+ */
+ public void apply(WireBuffer buffer,
+ float x1,
+ float y1) {
+ buffer.start(OP_CODE);
+ buffer.writeFloat(x1);
+ buffer.writeFloat(y1);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
new file mode 100644
index 0000000..56b2f1f
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Base class for commands that take 3 float
+ */
+public abstract class DrawBase3 extends PaintOperation
+ implements VariableSupport {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_CIRCLE) {
+ @Override
+ public Operation construct(float x1, float y1, float x2) {
+ // subclass should return new DrawX(x1, y1, x2, y2);
+ return null;
+ }
+ };
+ protected String mName = "DrawRectBase";
+ float mV1;
+ float mV2;
+ float mV3;
+ float mValue1;
+ float mValue2;
+ float mValue3;
+
+ public DrawBase3(
+ float v1,
+ float v2,
+ float v3) {
+ mValue1 = v1;
+ mValue2 = v2;
+ mValue3 = v3;
+
+ mV1 = v1;
+ mV2 = v2;
+ mV3 = v3;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ mV1 = (Float.isNaN(mValue1))
+ ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1;
+ mV2 = (Float.isNaN(mValue2))
+ ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2;
+ mV3 = (Float.isNaN(mValue3))
+ ? context.getFloat(Utils.idFromNan(mValue3)) : mValue3;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mValue1)) {
+ context.listensTo(Utils.idFromNan(mValue1), this);
+ }
+ if (Float.isNaN(mValue2)) {
+ context.listensTo(Utils.idFromNan(mValue2), this);
+ }
+ if (Float.isNaN(mValue3)) {
+ context.listensTo(Utils.idFromNan(mValue3), this);
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mV1, mV2, mV3);
+ }
+
+ @Override
+ public String toString() {
+ return mName + " " + floatToString(mV1) + " " + floatToString(mV2)
+ + " " + floatToString(mV3);
+ }
+
+ public static class Companion implements CompanionOperation {
+ public final int OP_CODE;
+
+ protected Companion(int code) {
+ OP_CODE = code;
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float v1 = buffer.readFloat();
+ float v2 = buffer.readFloat();
+ float v3 = buffer.readFloat();
+
+ Operation op = construct(v1, v2, v3);
+ operations.add(op);
+ }
+
+ /**
+ * Construct and Operation from the 3 variables.
+ * This must be overridden by subclasses
+ * @param x1
+ * @param y1
+ * @param x2
+ * @return
+ */
+ public Operation construct(float x1,
+ float y1,
+ float x2) {
+ return null;
+ }
+
+ @Override
+ public String name() {
+ return "DrawRect";
+ }
+
+ @Override
+ public int id() {
+ return OP_CODE;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param x1
+ * @param y1
+ * @param x2
+ */
+ public void apply(WireBuffer buffer,
+ float x1,
+ float y1,
+ float x2) {
+ buffer.start(OP_CODE);
+ buffer.writeFloat(x1);
+ buffer.writeFloat(y1);
+ buffer.writeFloat(x2);
+
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
new file mode 100644
index 0000000..ec35a16
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Base class for draw commands that take 4 floats
+ */
+public abstract class DrawBase4 extends PaintOperation
+ implements VariableSupport {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_RECT) {
+ @Override
+ public Operation construct(float x1, float y1, float x2, float y2) {
+ // return new DrawRectBase(x1, y1, x2, y2);
+ return null;
+ }
+ };
+ protected String mName = "DrawRectBase";
+ float mX1;
+ float mY1;
+ float mX2;
+ float mY2;
+ float mX1Value;
+ float mY1Value;
+ float mX2Value;
+ float mY2Value;
+
+ public DrawBase4(
+ float x1,
+ float y1,
+ float x2,
+ float y2) {
+ mX1Value = x1;
+ mY1Value = y1;
+ mX2Value = x2;
+ mY2Value = y2;
+
+ mX1 = x1;
+ mY1 = y1;
+ mX2 = x2;
+ mY2 = y2;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ mX1 = (Float.isNaN(mX1Value))
+ ? context.getFloat(Utils.idFromNan(mX1Value)) : mX1Value;
+ mY1 = (Float.isNaN(mY1Value))
+ ? context.getFloat(Utils.idFromNan(mY1Value)) : mY1Value;
+ mX2 = (Float.isNaN(mX2Value))
+ ? context.getFloat(Utils.idFromNan(mX2Value)) : mX2Value;
+ mY2 = (Float.isNaN(mY2Value))
+ ? context.getFloat(Utils.idFromNan(mY2Value)) : mY2Value;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mX1Value)) {
+ context.listensTo(Utils.idFromNan(mX1Value), this);
+ }
+ if (Float.isNaN(mY1Value)) {
+ context.listensTo(Utils.idFromNan(mY1Value), this);
+ }
+ if (Float.isNaN(mX2Value)) {
+ context.listensTo(Utils.idFromNan(mX2Value), this);
+ }
+ if (Float.isNaN(mY2Value)) {
+ context.listensTo(Utils.idFromNan(mY2Value), this);
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mX1, mY1, mX2, mY2);
+ }
+
+ @Override
+ public String toString() {
+ return mName + " " + floatToString(mX1Value, mX1) + " " + floatToString(mY1Value, mY1)
+ + " " + floatToString(mX2Value, mX2) + " " + floatToString(mY2Value, mY2);
+ }
+
+ public static class Companion implements CompanionOperation {
+ public final int OP_CODE;
+
+ protected Companion(int code) {
+ OP_CODE = code;
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float sLeft = buffer.readFloat();
+ float srcTop = buffer.readFloat();
+ float srcRight = buffer.readFloat();
+ float srcBottom = buffer.readFloat();
+
+ Operation op = construct(sLeft, srcTop, srcRight, srcBottom);
+ operations.add(op);
+ }
+
+ /**
+ * Construct and Operation from the 3 variables.
+ * @param x1
+ * @param y1
+ * @param x2
+ * @param y2
+ * @return
+ */
+ public Operation construct(float x1,
+ float y1,
+ float x2,
+ float y2) {
+ return null;
+ }
+
+ @Override
+ public String name() {
+ return "DrawRect";
+ }
+
+ @Override
+ public int id() {
+ return OP_CODE;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param x1
+ * @param y1
+ * @param x2
+ * @param y2
+ */
+ public void apply(WireBuffer buffer,
+ float x1,
+ float y1,
+ float x2,
+ float y2) {
+ buffer.start(OP_CODE);
+ buffer.writeFloat(x1);
+ buffer.writeFloat(y1);
+ buffer.writeFloat(x2);
+ buffer.writeFloat(y2);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
new file mode 100644
index 0000000..2f4335e
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Base class for draw commands the take 6 floats
+ */
+public abstract class DrawBase6 extends PaintOperation
+ implements VariableSupport {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_RECT) {
+ public Operation construct(float x1, float y1, float x2, float y2) {
+ // return new DrawRectBase(x1, y1, x2, y2);
+ return null;
+ }
+ };
+ protected String mName = "DrawRectBase";
+ float mV1;
+ float mV2;
+ float mV3;
+ float mV4;
+ float mV5;
+ float mV6;
+ float mValue1;
+ float mValue2;
+ float mValue3;
+ float mValue4;
+ float mValue5;
+ float mValue6;
+
+ public DrawBase6(
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ mValue1 = v1;
+ mValue2 = v2;
+ mValue3 = v3;
+ mValue4 = v4;
+ mValue5 = v5;
+ mValue6 = v6;
+
+ mV1 = v1;
+ mV2 = v2;
+ mV3 = v3;
+ mV4 = v4;
+ mV5 = v5;
+ mV6 = v6;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ mV1 = (Float.isNaN(mValue1))
+ ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1;
+ mV2 = (Float.isNaN(mValue2))
+ ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2;
+ mV3 = (Float.isNaN(mValue3))
+ ? context.getFloat(Utils.idFromNan(mValue3)) : mValue3;
+ mV4 = (Float.isNaN(mValue4))
+ ? context.getFloat(Utils.idFromNan(mValue4)) : mValue4;
+ mV5 = (Float.isNaN(mValue5))
+ ? context.getFloat(Utils.idFromNan(mValue5)) : mValue5;
+ mV6 = (Float.isNaN(mValue6))
+ ? context.getFloat(Utils.idFromNan(mValue6)) : mValue6;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mValue1)) {
+ context.listensTo(Utils.idFromNan(mValue1), this);
+ }
+ if (Float.isNaN(mValue2)) {
+ context.listensTo(Utils.idFromNan(mValue2), this);
+ }
+ if (Float.isNaN(mValue3)) {
+ context.listensTo(Utils.idFromNan(mValue3), this);
+ }
+ if (Float.isNaN(mValue4)) {
+ context.listensTo(Utils.idFromNan(mValue4), this);
+ }
+ if (Float.isNaN(mValue5)) {
+ context.listensTo(Utils.idFromNan(mValue5), this);
+ }
+ if (Float.isNaN(mValue6)) {
+ context.listensTo(Utils.idFromNan(mValue6), this);
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mV1, mV2, mV3, mV4, mV5, mV6);
+ }
+
+ @Override
+ public String toString() {
+ return mName + " " + floatToString(mV1) + " " + floatToString(mV2)
+ + " " + floatToString(mV3) + " " + floatToString(mV4);
+ }
+
+ public static class Companion implements CompanionOperation {
+ public final int OP_CODE;
+
+ protected Companion(int code) {
+ OP_CODE = code;
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float sv1 = buffer.readFloat();
+ float sv2 = buffer.readFloat();
+ float sv3 = buffer.readFloat();
+ float sv4 = buffer.readFloat();
+ float sv5 = buffer.readFloat();
+ float sv6 = buffer.readFloat();
+
+ Operation op = construct(sv1, sv2, sv3, sv4, sv5, sv6);
+ operations.add(op);
+ }
+
+ /**
+ * writes out a the operation to the buffer.
+ * @param v1
+ * @param v2
+ * @param v3
+ * @param v4
+ * @param v5
+ * @param v6
+ * @return
+ */
+ public Operation construct(float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ return null;
+ }
+
+ @Override
+ public String name() {
+ return "DrawRect";
+ }
+
+ @Override
+ public int id() {
+ return OP_CODE;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param v1
+ * @param v2
+ * @param v3
+ * @param v4
+ * @param v5
+ * @param v6
+ */
+ public void apply(WireBuffer buffer,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ buffer.start(OP_CODE);
+ buffer.writeFloat(v1);
+ buffer.writeFloat(v2);
+ buffer.writeFloat(v3);
+ buffer.writeFloat(v4);
+ buffer.writeFloat(v5);
+ buffer.writeFloat(v6);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
index 2e971f5..ca40d12 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
@@ -20,16 +20,22 @@
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import java.util.List;
-public class DrawBitmap extends PaintOperation {
+public class DrawBitmap extends PaintOperation implements VariableSupport {
public static final Companion COMPANION = new Companion();
float mLeft;
float mTop;
float mRight;
float mBottom;
+ float mOutputLeft;
+ float mOutputTop;
+ float mOutputRight;
+ float mOutputBottom;
int mId;
int mDescriptionId = 0;
@@ -49,6 +55,34 @@
}
@Override
+ public void updateVariables(RemoteContext context) {
+ mOutputLeft = (Float.isNaN(mLeft))
+ ? context.getFloat(Utils.idFromNan(mLeft)) : mLeft;
+ mOutputTop = (Float.isNaN(mTop))
+ ? context.getFloat(Utils.idFromNan(mTop)) : mTop;
+ mOutputRight = (Float.isNaN(mRight))
+ ? context.getFloat(Utils.idFromNan(mRight)) : mRight;
+ mOutputBottom = (Float.isNaN(mBottom))
+ ? context.getFloat(Utils.idFromNan(mBottom)) : mBottom;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mLeft)) {
+ context.listensTo(Utils.idFromNan(mLeft), this);
+ }
+ if (Float.isNaN(mTop)) {
+ context.listensTo(Utils.idFromNan(mTop), this);
+ }
+ if (Float.isNaN(mRight)) {
+ context.listensTo(Utils.idFromNan(mRight), this);
+ }
+ if (Float.isNaN(mBottom)) {
+ context.listensTo(Utils.idFromNan(mBottom), this);
+ }
+ }
+
+ @Override
public void write(WireBuffer buffer) {
COMPANION.apply(buffer, mId, mLeft, mTop, mRight, mBottom, mDescriptionId);
}
@@ -105,9 +139,9 @@
@Override
public void paint(PaintContext context) {
- context.drawBitmap(mId, mLeft,
- mTop,
- mRight,
- mBottom);
+ context.drawBitmap(mId, mOutputLeft,
+ mOutputTop,
+ mOutputRight,
+ mOutputBottom);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
index 9ce754d..3a22e4f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
@@ -1,89 +1,31 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
+public class DrawCircle extends DrawBase3 {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_CIRCLE) {
+ @Override
+ public Operation construct(float x1,
+ float y1,
+ float x2
+ ) {
+ return new DrawCircle(x1, y1, x2);
+ }
+ };
-public class DrawCircle extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mCenterX;
- float mCenterY;
- float mRadius;
-
- public DrawCircle(float centerX, float centerY, float radius) {
- mCenterX = centerX;
- mCenterY = centerY;
- mRadius = radius;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mCenterX,
- mCenterY,
- mRadius);
- }
-
- @Override
- public String toString() {
- return "";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float centerX = buffer.readFloat();
- float centerY = buffer.readFloat();
- float radius = buffer.readFloat();
-
- DrawCircle op = new DrawCircle(centerX, centerY, radius);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "";
- }
-
- @Override
- public int id() {
- return 0;
- }
-
- public void apply(WireBuffer buffer, float centerX, float centerY, float radius) {
- buffer.start(Operations.DRAW_CIRCLE);
- buffer.writeFloat(centerX);
- buffer.writeFloat(centerY);
- buffer.writeFloat(radius);
- }
+ public DrawCircle(
+ float left,
+ float top,
+ float right) {
+ super(left, top, right);
+ mName = "DrawCircle";
}
@Override
public void paint(PaintContext context) {
- context.drawCircle(mCenterX,
- mCenterY,
- mRadius);
+ context.drawCircle(mV1, mV2, mV3);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
index c7a8315..c70c6ea 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
@@ -15,83 +15,28 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class DrawLine extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mX1;
- float mY1;
- float mX2;
- float mY2;
+public class DrawLine extends DrawBase4 {
+ public static final Companion COMPANION = new Companion(Operations.DRAW_LINE) {
+ @Override
+ public Operation construct(float x1,
+ float y1,
+ float x2,
+ float y2) {
+ return new DrawLine(x1, y1, x2, y2);
+ }
+ };
public DrawLine(
- float x1,
- float y1,
- float x2,
- float y2) {
- mX1 = x1;
- mY1 = y1;
- mX2 = x2;
- mY2 = y2;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mX1,
- mY1,
- mX2,
- mY2);
- }
-
- @Override
- public String toString() {
- return "DrawArc " + mX1 + " " + mY1
- + " " + mX2 + " " + mY2 + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float x1 = buffer.readFloat();
- float y1 = buffer.readFloat();
- float x2 = buffer.readFloat();
- float y2 = buffer.readFloat();
-
- DrawLine op = new DrawLine(x1, y1, x2, y2);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "DrawLine";
- }
-
- @Override
- public int id() {
- return Operations.DRAW_LINE;
- }
-
- public void apply(WireBuffer buffer,
- float x1,
- float y1,
- float x2,
- float y2) {
- buffer.start(Operations.DRAW_LINE);
- buffer.writeFloat(x1);
- buffer.writeFloat(y1);
- buffer.writeFloat(x2);
- buffer.writeFloat(y2);
- }
+ float left,
+ float top,
+ float right,
+ float bottom) {
+ super(left, top, right, bottom);
+ mName = "DrawLine";
}
@Override
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
index 7143753..ba17994 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
@@ -15,88 +15,33 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class DrawOval extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mLeft;
- float mTop;
- float mRight;
- float mBottom;
-
+public class DrawOval extends DrawBase4 {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_OVAL) {
+ @Override
+ public Operation construct(float x1,
+ float y1,
+ float x2,
+ float y2) {
+ return new DrawOval(x1, y1, x2, y2);
+ }
+ };
public DrawOval(
float left,
float top,
float right,
float bottom) {
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom);
- }
-
- @Override
- public String toString() {
- return "DrawOval " + mLeft + " " + mTop
- + " " + mRight + " " + mBottom + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sLeft = buffer.readFloat();
- float srcTop = buffer.readFloat();
- float srcRight = buffer.readFloat();
- float srcBottom = buffer.readFloat();
-
- DrawOval op = new DrawOval(sLeft, srcTop, srcRight, srcBottom);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "DrawOval";
- }
-
- @Override
- public int id() {
- return Operations.DRAW_OVAL;
- }
-
- public void apply(WireBuffer buffer,
- float left,
- float top,
- float right,
- float bottom) {
- buffer.start(Operations.DRAW_OVAL);
- buffer.writeFloat(left);
- buffer.writeFloat(top);
- buffer.writeFloat(right);
- buffer.writeFloat(bottom);
- }
+ super(left, top, right, bottom);
+ mName = "DrawOval";
}
@Override
public void paint(PaintContext context) {
- context.drawOval(mLeft,
- mTop,
- mRight,
- mBottom);
+ context.drawOval(mX1, mY1, mX2, mY2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
index 7b8a9e9..6dbc5a6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
@@ -41,7 +41,7 @@
@Override
public String toString() {
- return "DrawPath " + ";";
+ return "DrawPath " + "[" + mId + "]" + ", " + mStart + ", " + mEnd;
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
index 4775241..633aed4 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
@@ -15,88 +15,37 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class DrawRect extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mLeft;
- float mTop;
- float mRight;
- float mBottom;
+/**
+ * Draw a Rectangle
+ */
+public class DrawRect extends DrawBase4 {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_RECT) {
+ @Override
+ public Operation construct(float x1,
+ float y1,
+ float x2,
+ float y2) {
+ return new DrawRect(x1, y1, x2, y2);
+ }
+ };
public DrawRect(
float left,
float top,
float right,
float bottom) {
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom);
- }
-
- @Override
- public String toString() {
- return "DrawRect " + mLeft + " " + mTop
- + " " + mRight + " " + mBottom + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sLeft = buffer.readFloat();
- float srcTop = buffer.readFloat();
- float srcRight = buffer.readFloat();
- float srcBottom = buffer.readFloat();
-
- DrawRect op = new DrawRect(sLeft, srcTop, srcRight, srcBottom);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "DrawRect";
- }
-
- @Override
- public int id() {
- return Operations.DRAW_RECT;
- }
-
- public void apply(WireBuffer buffer,
- float left,
- float top,
- float right,
- float bottom) {
- buffer.start(Operations.DRAW_RECT);
- buffer.writeFloat(left);
- buffer.writeFloat(top);
- buffer.writeFloat(right);
- buffer.writeFloat(bottom);
- }
+ super(left, top, right, bottom);
+ mName = "DrawRect";
}
@Override
public void paint(PaintContext context) {
- context.drawRect(mLeft,
- mTop,
- mRight,
- mBottom);
+ context.drawRect(mX1, mY1, mX2, mY2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
index 8da16e7..b9d0a67 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
@@ -15,104 +15,40 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
+/**
+ * Draw a rounded rectangle
+ */
+public class DrawRoundRect extends DrawBase6 {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_ROUND_RECT) {
+ @Override
+ public Operation construct(float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ return new DrawRoundRect(v1, v2, v3, v4, v5, v6);
+ }
+ };
-public class DrawRoundRect extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mLeft;
- float mTop;
- float mRight;
- float mBottom;
- float mRadiusX;
- float mRadiusY;
-
- public DrawRoundRect(
- float left,
- float top,
- float right,
- float bottom,
- float radiusX,
- float radiusY) {
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
- mRadiusX = radiusX;
- mRadiusY = radiusY;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom, mRadiusX, mRadiusY);
- }
-
- @Override
- public String toString() {
- return "DrawRoundRect " + mLeft + " " + mTop
- + " " + mRight + " " + mBottom
- + " (" + mRadiusX + " " + mRadiusY + ");";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sLeft = buffer.readFloat();
- float srcTop = buffer.readFloat();
- float srcRight = buffer.readFloat();
- float srcBottom = buffer.readFloat();
- float srcRadiusX = buffer.readFloat();
- float srcRadiusY = buffer.readFloat();
-
- DrawRoundRect op = new DrawRoundRect(sLeft, srcTop, srcRight,
- srcBottom, srcRadiusX, srcRadiusY);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "DrawOval";
- }
-
- @Override
- public int id() {
- return Operations.DRAW_ROUND_RECT;
- }
-
- public void apply(WireBuffer buffer,
- float left,
- float top,
- float right,
- float bottom,
- float radiusX,
- float radiusY) {
- buffer.start(Operations.DRAW_ROUND_RECT);
- buffer.writeFloat(left);
- buffer.writeFloat(top);
- buffer.writeFloat(right);
- buffer.writeFloat(bottom);
- buffer.writeFloat(radiusX);
- buffer.writeFloat(radiusY);
- }
+ public DrawRoundRect(float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ super(v1, v2, v3, v4, v5, v6);
+ mName = "ClipRect";
}
@Override
public void paint(PaintContext context) {
- context.drawRoundRect(mLeft,
- mTop,
- mRight,
- mBottom,
- mRadiusX,
- mRadiusY
+ context.drawRoundRect(mV1, mV2, mV3, mV4, mV5, mV6
);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
new file mode 100644
index 0000000..f8f8afd
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Draw Text
+ */
+public class DrawText extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ int mTextID;
+ int mStart = 0;
+ int mEnd = 0;
+ int mContextStart = 0;
+ int mContextEnd = 0;
+ float mX = 0f;
+ float mY = 0f;
+ boolean mRtl = false;
+
+ public DrawText(int textID,
+ int start,
+ int end,
+ int contextStart,
+ int contextEnd,
+ float x,
+ float y,
+ boolean rtl) {
+ mTextID = textID;
+ mStart = start;
+ mEnd = end;
+ mContextStart = contextStart;
+ mContextEnd = contextEnd;
+ mX = x;
+ mY = y;
+ mRtl = rtl;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mTextID, mStart, mEnd, mContextStart, mContextEnd, mX, mY, mRtl);
+
+ }
+
+ @Override
+ public String toString() {
+ return "DrawTextRun [" + mTextID + "] " + mStart + ", " + mEnd + ", " + mX + ", " + mY;
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int text = buffer.readInt();
+ int start = buffer.readInt();
+ int end = buffer.readInt();
+ int contextStart = buffer.readInt();
+ int contextEnd = buffer.readInt();
+ float x = buffer.readFloat();
+ float y = buffer.readFloat();
+ boolean rtl = buffer.readBoolean();
+ DrawText op = new DrawText(text, start, end, contextStart, contextEnd, x, y, rtl);
+
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "";
+ }
+
+ @Override
+ public int id() {
+ return 0;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param textID
+ * @param start
+ * @param end
+ * @param contextStart
+ * @param contextEnd
+ * @param x
+ * @param y
+ * @param rtl
+ */
+ public void apply(WireBuffer buffer,
+ int textID,
+ int start,
+ int end,
+ int contextStart,
+ int contextEnd,
+ float x,
+ float y,
+ boolean rtl) {
+ buffer.start(Operations.DRAW_TEXT_RUN);
+ buffer.writeInt(textID);
+ buffer.writeInt(start);
+ buffer.writeInt(end);
+ buffer.writeInt(contextStart);
+ buffer.writeInt(contextEnd);
+ buffer.writeFloat(x);
+ buffer.writeFloat(y);
+ buffer.writeBoolean(rtl);
+ }
+ }
+
+ @Override
+ public void paint(PaintContext context) {
+ context.drawTextRun(mTextID, mStart, mEnd, mContextStart, mContextEnd, mX, mY, mRtl);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
new file mode 100644
index 0000000..4f0641f
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Draw Text in Anchored to a point
+ */
+public class DrawTextAnchored extends PaintOperation implements VariableSupport {
+ public static final Companion COMPANION = new Companion();
+ int mTextID;
+ float mX;
+ float mY;
+ float mPanX;
+ float mPanY;
+ int mFlags;
+ float mOutX;
+ float mOutY;
+ float mOutPanX;
+ float mOutPanY;
+
+ public static final int ANCHOR_TEXT_RTL = 1;
+ public static final int ANCHOR_MONOSPACE_MEASURE = 2;
+
+ public DrawTextAnchored(int textID,
+ float x,
+ float y,
+ float panX,
+ float panY,
+ int flags) {
+ mTextID = textID;
+ mX = x;
+ mY = y;
+ mOutX = mX;
+ mOutY = mY;
+ mFlags = flags;
+ mOutPanX = mPanX = panX;
+ mOutPanY = mPanY = panY;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ mOutX = (Float.isNaN(mX))
+ ? context.getFloat(Utils.idFromNan(mX)) : mX;
+ mOutY = (Float.isNaN(mY))
+ ? context.getFloat(Utils.idFromNan(mY)) : mY;
+ mOutPanX = (Float.isNaN(mPanX))
+ ? context.getFloat(Utils.idFromNan(mPanX)) : mPanX;
+ mOutPanY = (Float.isNaN(mPanY))
+ ? context.getFloat(Utils.idFromNan(mPanY)) : mPanY;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mX)) {
+ context.listensTo(Utils.idFromNan(mX), this);
+ }
+ if (Float.isNaN(mY)) {
+ context.listensTo(Utils.idFromNan(mY), this);
+ }
+ if (Float.isNaN(mPanX)) {
+ context.listensTo(Utils.idFromNan(mPanX), this);
+ }
+ if (Float.isNaN(mPanY) && Utils.idFromNan(mPanY) > 0) {
+ context.listensTo(Utils.idFromNan(mPanY), this);
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mTextID, mX,
+ mY,
+ mPanX,
+ mPanY,
+ mFlags);
+ }
+
+ @Override
+ public String toString() {
+ return "DrawTextAnchored [" + mTextID + "] " + floatToStr(mX) + ", "
+ + floatToStr(mY) + ", "
+ + floatToStr(mPanX) + ", " + floatToStr(mPanY) + ", "
+ + Integer.toBinaryString(mFlags);
+ }
+
+ private static String floatToStr(float v) {
+ if (Float.isNaN(v)) {
+ return "[" + Utils.idFromNan(v) + "]";
+ }
+ return Float.toString(v);
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int textID = buffer.readInt();
+ float x = buffer.readFloat();
+ float y = buffer.readFloat();
+ float panX = buffer.readFloat();
+ float panY = buffer.readFloat();
+ int flags = buffer.readInt();
+
+ DrawTextAnchored op = new DrawTextAnchored(textID,
+ x, y,
+ panX, panY,
+ flags);
+
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "";
+ }
+
+ @Override
+ public int id() {
+ return 0;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param textID
+ * @param x
+ * @param y
+ * @param panX
+ * @param panY
+ * @param flags
+ */
+ public void apply(WireBuffer buffer,
+ int textID,
+ float x,
+ float y,
+ float panX,
+ float panY,
+ int flags) {
+ buffer.start(Operations.DRAW_TEXT_ANCHOR);
+ buffer.writeInt(textID);
+ buffer.writeFloat(x);
+ buffer.writeFloat(y);
+ buffer.writeFloat(panX);
+ buffer.writeFloat(panY);
+ buffer.writeInt(flags);
+ }
+ }
+
+ float[] mBounds = new float[4];
+
+ private float getHorizontalOffset() {
+ // TODO scale TextSize / BaseTextSize;
+ float scale = 1.0f;
+
+ float textWidth = scale * (mBounds[2] - mBounds[0]);
+ float boxWidth = 0;
+ return (boxWidth - textWidth) * (1 + mOutPanX) / 2.f
+ - (scale * mBounds[0]);
+ }
+
+ private float getVerticalOffset() {
+ // TODO scale TextSize / BaseTextSize;
+ float scale = 1.0f;
+ float boxHeight = 0;
+ float textHeight = scale * (mBounds[3] - mBounds[1]);
+ return (boxHeight - textHeight) * (1 - mOutPanY) / 2
+ - (scale * mBounds[1]);
+ }
+
+ @Override
+ public void paint(PaintContext context) {
+ context.getTextBounds(mTextID, 0, -1,
+ (mFlags & ANCHOR_MONOSPACE_MEASURE) != 0, mBounds);
+ float x = mOutX + getHorizontalOffset();
+ float y = (Float.isNaN(mOutPanY)) ? mOutY : mOutY + getVerticalOffset();
+ context.drawTextRun(mTextID, 0, -1, 0, 1, x, y,
+ (mFlags & ANCHOR_TEXT_RTL) == 1);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
index 1856e30..b1a0172 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
@@ -24,6 +24,9 @@
import java.util.List;
+/**
+ * Draw text along a path.
+ */
public class DrawTextOnPath extends PaintOperation {
public static final Companion COMPANION = new Companion();
int mPathId;
@@ -45,7 +48,8 @@
@Override
public String toString() {
- return "DrawTextOnPath " + " " + mPathId + ";";
+ return "DrawTextOnPath [" + mTextId + "] [" + mPathId + "] "
+ + mHOffset + ", " + mVOffset;
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
index ef0a4ad..48fc94e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
@@ -58,7 +58,7 @@
public String toString() {
return "DrawTweenPath " + mPath1Id + " " + mPath2Id
+ " " + mTween + " " + mStart + " "
- + "- " + mStop + ";";
+ + "- " + mStop;
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
new file mode 100644
index 0000000..576b53f
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Operation to deal with Text data
+ */
+public class FloatConstant implements Operation {
+ public int mTextId;
+ public float mValue;
+ public static final Companion COMPANION = new Companion();
+ public static final int MAX_STRING_SIZE = 4000;
+
+ public FloatConstant(int textId, float value) {
+ this.mTextId = textId;
+ this.mValue = value;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mTextId, mValue);
+ }
+
+ @Override
+ public String toString() {
+ return "FloatConstant[" + mTextId + "] = " + mValue + "";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {}
+
+ @Override
+ public String name() {
+ return "FloatExpression";
+ }
+
+ @Override
+ public int id() {
+ return Operations.DATA_FLOAT;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param textId
+ * @param value
+ */
+ public void apply(WireBuffer buffer, int textId, float value) {
+ buffer.start(Operations.DATA_FLOAT);
+ buffer.writeInt(textId);
+ buffer.writeFloat(value);
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int textId = buffer.readInt();
+
+ float value = buffer.readFloat();
+ operations.add(new FloatConstant(textId, value));
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ context.loadFloat(mTextId, mValue);
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
new file mode 100644
index 0000000..354f41b
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression;
+import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Operation to deal with AnimatedFloats
+ * This is designed to be an optimized calculation for things like
+ * injecting the width of the component int draw rect
+ * As well as supporting generalized animation floats.
+ * The floats represent a RPN style calculator
+ */
+public class FloatExpression implements Operation, VariableSupport {
+ public int mId;
+ public float[] mSrcValue;
+ public float[] mSrcAnimation;
+ public FloatAnimation mFloatAnimation;
+ public float[] mPreCalcValue;
+ private float mLastChange = Float.NaN;
+ AnimatedFloatExpression mExp = new AnimatedFloatExpression();
+ public static final Companion COMPANION = new Companion();
+ public static final int MAX_STRING_SIZE = 4000;
+
+ public FloatExpression(int id, float[] value, float[] animation) {
+ this.mId = id;
+ this.mSrcValue = value;
+ this.mSrcAnimation = animation;
+ if (mSrcAnimation != null) {
+ mFloatAnimation = new FloatAnimation(mSrcAnimation);
+ }
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ if (mPreCalcValue == null || mPreCalcValue.length != mSrcValue.length) {
+ mPreCalcValue = new float[mSrcValue.length];
+ }
+ //Utils.log("updateVariables ");
+ boolean value_changed = false;
+ for (int i = 0; i < mSrcValue.length; i++) {
+ float v = mSrcValue[i];
+ if (Float.isNaN(v) && !AnimatedFloatExpression.isMathOperator(v)) {
+ float newValue = context.getFloat(Utils.idFromNan(v));
+ if (mFloatAnimation != null) {
+ if (mPreCalcValue[i] != newValue) {
+ mLastChange = context.getAnimationTime();
+ value_changed = true;
+ mPreCalcValue[i] = newValue;
+ }
+ } else {
+ mPreCalcValue[i] = newValue;
+ }
+ } else {
+ mPreCalcValue[i] = mSrcValue[i];
+ }
+ }
+ if (value_changed && mFloatAnimation != null) {
+ float v = mExp.eval(Arrays.copyOf(mPreCalcValue, mPreCalcValue.length));
+ if (Float.isNaN(mFloatAnimation.getTargetValue())) {
+ mFloatAnimation.setInitialValue(v);
+ } else {
+ mFloatAnimation.setInitialValue(mFloatAnimation.getTargetValue());
+ }
+ mFloatAnimation.setTargetValue(v);
+ }
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ for (int i = 0; i < mSrcValue.length; i++) {
+ float v = mSrcValue[i];
+ if (Float.isNaN(v) && !AnimatedFloatExpression.isMathOperator(v)) {
+ context.listensTo(Utils.idFromNan(v), this);
+ }
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ updateVariables(context);
+ float t = context.getAnimationTime();
+ if (Float.isNaN(mLastChange)) {
+ mLastChange = t;
+ }
+ if (mFloatAnimation != null) {
+ float f = mFloatAnimation.get(t - mLastChange);
+ context.loadFloat(mId, f);
+ } else {
+ context.loadFloat(mId, mExp.eval(Arrays.copyOf(mPreCalcValue, mPreCalcValue.length)));
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mId, mSrcValue, mSrcAnimation);
+ }
+
+ @Override
+ public String toString() {
+ String[] labels = new String[mSrcValue.length];
+ for (int i = 0; i < mSrcValue.length; i++) {
+ if (Float.isNaN(mSrcValue[i])) {
+ labels[i] = "[" + Utils.idFromNan(mSrcValue[i]) + "]";
+ }
+
+ }
+ return "FloatExpression[" + mId + "] = ("
+ + AnimatedFloatExpression.toString(mPreCalcValue, labels) + ")";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "FloatExpression";
+ }
+
+ @Override
+ public int id() {
+ return Operations.ANIMATED_FLOAT;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param id
+ * @param value
+ * @param animation
+ */
+ public void apply(WireBuffer buffer, int id, float[] value, float[] animation) {
+ buffer.start(Operations.ANIMATED_FLOAT);
+ buffer.writeInt(id);
+
+ int len = value.length;
+ if (animation != null) {
+ len |= (animation.length << 16);
+ }
+ buffer.writeInt(len);
+
+ for (int i = 0; i < value.length; i++) {
+ buffer.writeFloat(value[i]);
+ }
+ if (animation != null) {
+ for (int i = 0; i < animation.length; i++) {
+ buffer.writeFloat(animation[i]);
+ }
+ }
+
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int id = buffer.readInt();
+ int len = buffer.readInt();
+ int valueLen = len & 0xFFFF;
+ int animLen = (len >> 16) & 0xFFFF;
+ float[] values = new float[valueLen];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = buffer.readFloat();
+ }
+
+ float[] animation;
+ if (animLen != 0) {
+ animation = new float[animLen];
+ for (int i = 0; i < animation.length; i++) {
+ animation[i] = buffer.readFloat();
+ }
+ } else {
+ animation = null;
+ }
+ operations.add(new FloatExpression(id, values, animation));
+ }
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
index 482e0e2..0dad45c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
@@ -37,7 +37,7 @@
@Override
public String toString() {
- return "MatrixRestore;";
+ return "MatrixRestore";
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
index d6c89e0..bbf4135 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
@@ -15,68 +15,29 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class MatrixRotate extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mRotate, mPivotX, mPivotY;
+public class MatrixRotate extends DrawBase3 {
+ public static final Companion COMPANION =
+ new Companion(Operations.MATRIX_ROTATE) {
+ @Override
+ public Operation construct(float rotate,
+ float pivotX,
+ float pivotY
+ ) {
+ return new MatrixRotate(rotate, pivotX, pivotY);
+ }
+ };
public MatrixRotate(float rotate, float pivotX, float pivotY) {
- mRotate = rotate;
- mPivotX = pivotX;
- mPivotY = pivotY;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mRotate, mPivotX, mPivotY);
- }
-
- @Override
- public String toString() {
- return "DrawArc " + mRotate + ", " + mPivotX + ", " + mPivotY + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float rotate = buffer.readFloat();
- float pivotX = buffer.readFloat();
- float pivotY = buffer.readFloat();
- MatrixRotate op = new MatrixRotate(rotate, pivotX, pivotY);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "Matrix";
- }
-
- @Override
- public int id() {
- return Operations.MATRIX_ROTATE;
- }
-
- public void apply(WireBuffer buffer, float rotate, float pivotX, float pivotY) {
- buffer.start(Operations.MATRIX_ROTATE);
- buffer.writeFloat(rotate);
- buffer.writeFloat(pivotX);
- buffer.writeFloat(pivotY);
- }
+ super(rotate, pivotX, pivotY);
+ mName = "MatrixRotate";
}
@Override
public void paint(PaintContext context) {
- context.matrixRotate(mRotate, mPivotX, mPivotY);
+ context.matrixRotate(mV1, mV2, mV3);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
index 28aa68dd..04b940b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
@@ -15,74 +15,30 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class MatrixScale extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mScaleX, mScaleY;
- float mCenterX, mCenterY;
+public class MatrixScale extends DrawBase4 {
+ public static final Companion COMPANION =
+ new Companion(Operations.MATRIX_SCALE) {
+ @Override
+ public Operation construct(float scaleX,
+ float scaleY,
+ float centerX,
+ float centerY
+ ) {
+ return new MatrixScale(scaleX, scaleY, centerX, centerY);
+ }
+ };
public MatrixScale(float scaleX, float scaleY, float centerX, float centerY) {
- mScaleX = scaleX;
- mScaleY = scaleY;
- mCenterX = centerX;
- mCenterY = centerY;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mScaleX, mScaleY, mCenterX, mCenterY);
- }
-
- @Override
- public String toString() {
- return "MatrixScale " + mScaleY + ", " + mScaleY + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float scaleX = buffer.readFloat();
- float scaleY = buffer.readFloat();
- float centerX = buffer.readFloat();
- float centerY = buffer.readFloat();
- MatrixScale op = new MatrixScale(scaleX, scaleY, centerX, centerY);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "Matrix";
- }
-
- @Override
- public int id() {
- return Operations.MATRIX_SCALE;
- }
-
- public void apply(WireBuffer buffer, float scaleX, float scaleY,
- float centerX, float centerY) {
- buffer.start(Operations.MATRIX_SCALE);
- buffer.writeFloat(scaleX);
- buffer.writeFloat(scaleY);
- buffer.writeFloat(centerX);
- buffer.writeFloat(centerY);
-
- }
+ super(scaleX, scaleY, centerX, centerY);
+ mName = "MatrixScale";
}
@Override
public void paint(PaintContext context) {
- context.mtrixScale(mScaleX, mScaleY, mCenterX, mCenterY);
+ context.matrixScale(mX1, mY1, mX2, mY2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
index 3298752..4f34e98 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
@@ -15,65 +15,28 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class MatrixTranslate extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mTranslateX, mTranslateY;
+public class MatrixTranslate extends DrawBase2 {
+ public static final Companion COMPANION =
+ new Companion(Operations.MATRIX_TRANSLATE) {
+ @Override
+ public Operation construct(float x1,
+ float y1
+ ) {
+ return new MatrixTranslate(x1, y1);
+ }
+ };
public MatrixTranslate(float translateX, float translateY) {
- mTranslateX = translateX;
- mTranslateY = translateY;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mTranslateX, mTranslateY);
- }
-
- @Override
- public String toString() {
- return "DrawArc " + mTranslateY + ", " + mTranslateY + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float translateX = buffer.readFloat();
- float translateY = buffer.readFloat();
- MatrixTranslate op = new MatrixTranslate(translateX, translateY);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "Matrix";
- }
-
- @Override
- public int id() {
- return Operations.MATRIX_TRANSLATE;
- }
-
- public void apply(WireBuffer buffer, float translateX, float translateY) {
- buffer.start(Operations.MATRIX_TRANSLATE);
- buffer.writeFloat(translateX);
- buffer.writeFloat(translateY);
- }
+ super(translateX, translateY);
+ mName = "MatrixTranslate";
}
@Override
public void paint(PaintContext context) {
- context.matrixTranslate(mTranslateX, mTranslateY);
+ context.matrixTranslate(mV1, mV2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
new file mode 100644
index 0000000..0c5b286
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Operation to deal with Text data
+ */
+public class NamedVariable implements Operation {
+ public int mVarId;
+ public String mVarName;
+ public int mVarType;
+ public static final Companion COMPANION = new Companion();
+ public static final int MAX_STRING_SIZE = 4000;
+
+ public NamedVariable(int varId, int varType, String name) {
+ this.mVarId = varId;
+ this.mVarType = varType;
+ this.mVarName = name;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mVarId, mVarType, mVarName);
+ }
+
+ @Override
+ public String toString() {
+ return "VariableName[" + mVarId + "] = \""
+ + Utils.trimString(mVarName, 10) + "\" type=" + mVarType;
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "TextData";
+ }
+
+ @Override
+ public int id() {
+ return Operations.DATA_TEXT;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param varId
+ * @param varType
+ * @param text
+ */
+ public void apply(WireBuffer buffer, int varId, int varType, String text) {
+ buffer.start(Operations.DATA_TEXT);
+ buffer.writeInt(varId);
+ buffer.writeInt(varType);
+ buffer.writeUTF8(text);
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int varId = buffer.readInt();
+ int varType = buffer.readInt();
+ String text = buffer.readUTF8(MAX_STRING_SIZE);
+ operations.add(new NamedVariable(varId, varType, text));
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ context.loadVariableName(mVarName, mVarId, mVarType);
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
index e5683ec..0807bcd 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
@@ -20,12 +20,14 @@
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
import java.util.List;
-public class PaintData extends PaintOperation {
+public class PaintData extends PaintOperation implements VariableSupport {
public PaintBundle mPaintData = new PaintBundle();
public static final Companion COMPANION = new Companion();
public static final int MAX_STRING_SIZE = 4000;
@@ -34,6 +36,16 @@
}
@Override
+ public void updateVariables(RemoteContext context) {
+ mPaintData.updateVariables(context);
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ mPaintData.registerVars(context, this);
+ }
+
+ @Override
public void write(WireBuffer buffer) {
COMPANION.apply(buffer, mPaintData);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
index 2646b27..e467e7b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
@@ -18,27 +18,50 @@
import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
+import java.util.Arrays;
import java.util.List;
-public class PathData implements Operation {
+public class PathData implements Operation, VariableSupport {
public static final Companion COMPANION = new Companion();
int mInstanceId;
- float[] mRef;
float[] mFloatPath;
- float[] mRetFloats;
+ float[] mOutputPath;
PathData(int instanceId, float[] floatPath) {
mInstanceId = instanceId;
mFloatPath = floatPath;
+ mOutputPath = Arrays.copyOf(mFloatPath, mFloatPath.length);
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ for (int i = 0; i < mFloatPath.length; i++) {
+ float v = mFloatPath[i];
+ if (Utils.isVariable(v)) {
+ mOutputPath[i] = (Float.isNaN(v))
+ ? context.getFloat(Utils.idFromNan(v)) : v;
+ } else {
+ mOutputPath[i] = v;
+ }
+ }
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ for (int i = 0; i < mFloatPath.length; i++) {
+ if (Float.isNaN(mFloatPath[i])) {
+ context.listensTo(Utils.idFromNan(mFloatPath[i]), this);
+ }
+ }
}
@Override
public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mInstanceId, mFloatPath);
+ COMPANION.apply(buffer, mInstanceId, mOutputPath);
}
@Override
@@ -46,29 +69,35 @@
return pathString(mFloatPath);
}
- public float[] getFloatPath(PaintContext context) {
- float[] ret = mRetFloats; // Assume retFloats is declared elsewhere
- if (ret == null) {
- return mFloatPath; // Assume floatPath is declared elsewhere
- }
- float[] localRef = mRef; // Assume ref is of type Float[]
- if (localRef == null) {
- for (int i = 0; i < mFloatPath.length; i++) {
- ret[i] = mFloatPath[i];
- }
- } else {
- for (int i = 0; i < mFloatPath.length; i++) {
- float lr = localRef[i];
- if (Float.isNaN(lr)) {
- ret[i] = Utils.getActualValue(lr);
- } else {
- ret[i] = mFloatPath[i];
- }
- }
- }
- return ret;
+ @Override
+ public String toString() {
+ return "PathData[" + mInstanceId + "] = " + "\"" + deepToString(" ") + "\"";
}
+ /**
+ * public float[] getFloatPath(PaintContext context) {
+ * float[] ret = mRetFloats; // Assume retFloats is declared elsewhere
+ * if (ret == null) {
+ * return mFloatPath; // Assume floatPath is declared elsewhere
+ * }
+ * float[] localRef = mRef; // Assume ref is of type Float[]
+ * if (localRef == null) {
+ * for (int i = 0; i < mFloatPath.length; i++) {
+ * ret[i] = mFloatPath[i];
+ * }
+ * } else {
+ * for (int i = 0; i < mFloatPath.length; i++) {
+ * float lr = localRef[i];
+ * if (Float.isNaN(lr)) {
+ * ret[i] = Utils.getActualValue(lr);
+ * } else {
+ * ret[i] = mFloatPath[i];
+ * }
+ * }
+ * }
+ * return ret;
+ * }
+ */
public static final int MOVE = 10;
public static final int LINE = 11;
public static final int QUADRATIC = 12;
@@ -155,7 +184,7 @@
str.append(".");
break;
default:
- str.append("X");
+ str.append("[" + id + "]");
break;
}
} else {
@@ -170,7 +199,7 @@
@Override
public void apply(RemoteContext context) {
- context.loadPathData(mInstanceId, mFloatPath);
+ context.loadPathData(mInstanceId, mOutputPath);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
index 6d924eb..997e8dc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
@@ -94,7 +94,6 @@
public static final int SCALE_CROP = 5;
public static final int SCALE_FILL_BOUNDS = 6;
-
public static final Companion COMPANION = new Companion();
/**
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
index 64c7f3e..076b28e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
@@ -48,7 +48,7 @@
@Override
public String toString() {
- return "ROOT_CONTENT_DESCRIPTION " + mContentDescription;
+ return "RootContentDescription " + mContentDescription;
}
@Override
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
new file mode 100644
index 0000000..8463ac5
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Operation to deal with bitmap data
+ * On getting an Image during a draw call the bitmap is compressed and saved
+ * in playback the image is decompressed
+ */
+public class ShaderData implements Operation, VariableSupport {
+ int mShaderTextId; // the actual text of a shader
+ int mShaderID; // allows shaders to be referenced by number
+ HashMap<String, float[]> mUniformRawFloatMap = null;
+ HashMap<String, float[]> mUniformFloatMap = null;
+ HashMap<String, int[]> mUniformIntMap = null;
+ HashMap<String, Integer> mUniformBitmapMap = null;
+
+ public static final int MAX_IMAGE_DIMENSION = 8000;
+
+ public static final Companion COMPANION = new Companion();
+
+ public ShaderData(int shaderID,
+ int shaderTextId,
+ HashMap<String, float[]> floatMap,
+ HashMap<String, int[]> intMap,
+ HashMap<String, Integer> bitmapMap) {
+ mShaderID = shaderID;
+ mShaderTextId = shaderTextId;
+ if (floatMap != null) {
+ mUniformFloatMap = new HashMap<>();
+ mUniformRawFloatMap = new HashMap<>();
+
+ for (String name : floatMap.keySet()) {
+ mUniformRawFloatMap.put(name, floatMap.get(name));
+ mUniformFloatMap.put(name, floatMap.get(name));
+ }
+ }
+
+ if (intMap != null) {
+ mUniformIntMap = new HashMap<>();
+ for (String name : intMap.keySet()) {
+ mUniformIntMap.put(name, intMap.get(name));
+ }
+ }
+ if (bitmapMap != null) {
+ mUniformBitmapMap = new HashMap<>();
+ for (String name : bitmapMap.keySet()) {
+ mUniformBitmapMap.put(name, bitmapMap.get(name));
+ }
+ }
+
+ }
+
+ public int getShaderTextId() {
+ return mShaderTextId;
+ }
+
+ /**
+ * get names of all known floats
+ * @return
+ */
+ public String[] getUniformFloatNames() {
+ if (mUniformFloatMap == null) return new String[0];
+ return mUniformFloatMap.keySet().toArray(new String[0]);
+ }
+
+ /**
+ * Get float values associated with the name
+ * @param name
+ * @return
+ */
+ public float[] getUniformFloats(String name) {
+ return mUniformFloatMap.get(name);
+ }
+
+ /**
+ * get the name of all know uniform integers
+ * @return
+ */
+ public String[] getUniformIntegerNames() {
+ if (mUniformIntMap == null) return new String[0];
+ return mUniformIntMap.keySet().toArray(new String[0]);
+ }
+
+ /**
+ * Get Int value associated with the name
+ * @param name
+ * @return
+ */
+ public int[] getUniformInts(String name) {
+ return mUniformIntMap.get(name);
+ }
+
+ /**
+ * get list of uniform Bitmaps
+ * @return
+ */
+ public String[] getUniformBitmapNames() {
+ if (mUniformBitmapMap == null) return new String[0];
+ return mUniformBitmapMap.keySet().toArray(new String[0]);
+ }
+
+ /**
+ * Get a bitmap stored under that name
+ * @param name
+ * @return
+ */
+ public int getUniformBitmapId(String name) {
+ return mUniformBitmapMap.get(name);
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mShaderID, mShaderTextId,
+ mUniformFloatMap, mUniformIntMap, mUniformBitmapMap);
+ }
+
+ @Override
+ public String toString() {
+ return "SHADER DATA " + mShaderID;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ for (String name : mUniformRawFloatMap.keySet()) {
+ float[] value = mUniformRawFloatMap.get(name);
+ float[] out = null;
+ for (int i = 0; i < value.length; i++) {
+ if (Float.isNaN(value[i])) {
+ if (out == null) { // need to copy
+ out = Arrays.copyOf(value, value.length);
+ }
+ out[i] = context.getFloat(Utils.idFromNan(value[i]));
+ }
+ }
+ mUniformFloatMap.put(name, out == null ? value : out);
+ }
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ for (String name : mUniformRawFloatMap.keySet()) {
+ float[] value = mUniformRawFloatMap.get(name);
+ for (int i = 0; i < value.length; i++) {
+ if (Float.isNaN(value[i])) {
+ context.listensTo(Utils.idFromNan(value[i]), this);
+ }
+ }
+ }
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "BitmapData";
+ }
+
+ @Override
+ public int id() {
+ return Operations.DATA_SHADER;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param shaderID
+ * @param shaderTextId
+ * @param floatMap
+ * @param intMap
+ * @param bitmapMap
+ */
+ public void apply(WireBuffer buffer, int shaderID, int shaderTextId,
+ HashMap<String, float[]> floatMap,
+ HashMap<String, int[]> intMap,
+ HashMap<String, Integer> bitmapMap) {
+ buffer.start(Operations.DATA_SHADER);
+ buffer.writeInt(shaderID);
+
+ buffer.writeInt(shaderTextId);
+ int floatSize = (floatMap == null) ? 0 : floatMap.size();
+ int intSize = (intMap == null) ? 0 : intMap.size();
+ int bitmapSize = (bitmapMap == null) ? 0 : bitmapMap.size();
+ int sizes = floatSize | (intSize << 8) | (bitmapSize << 16);
+ buffer.writeInt(sizes);
+
+ if (floatSize > 0) {
+
+ for (String name : floatMap.keySet()) {
+ buffer.writeUTF8(name);
+ float[] values = floatMap.get(name);
+ buffer.writeInt(values.length);
+
+ for (int i = 0; i < values.length; i++) {
+ buffer.writeFloat(values[i]);
+ }
+ }
+ }
+
+ if (intSize > 0) {
+ for (String name : intMap.keySet()) {
+ buffer.writeUTF8(name);
+ int[] values = intMap.get(name);
+ buffer.writeInt(values.length);
+ for (int i = 0; i < values.length; i++) {
+ buffer.writeInt(values[i]);
+ }
+ }
+ }
+ if (bitmapSize > 0) {
+ for (String name : bitmapMap.keySet()) {
+ buffer.writeUTF8(name);
+ int value = bitmapMap.get(name);
+ buffer.writeInt(value);
+ }
+ }
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int shaderID = buffer.readInt();
+ int shaderTextId = buffer.readInt();
+ HashMap<String, float[]> floatMap = null;
+ HashMap<String, int[]> intMap = null;
+ HashMap<String, Integer> bitmapMap = null;
+
+ int sizes = buffer.readInt();
+
+ int floatMapSize = sizes & 0xFF;
+ if (floatMapSize > 0) {
+ floatMap = new HashMap<>();
+ for (int i = 0; i < floatMapSize; i++) {
+ String name = buffer.readUTF8();
+ int len = buffer.readInt();
+ float[] val = new float[len];
+
+ for (int j = 0; j < len; j++) {
+ val[j] = buffer.readFloat();
+ }
+
+ floatMap.put(name, val);
+ }
+ }
+ int intMapSize = (sizes >> 8) & 0xFF;
+
+ if (intMapSize > 0) {
+
+ intMap = new HashMap<>();
+ for (int i = 0; i < intMapSize; i++) {
+ String name = buffer.readUTF8();
+ int len = buffer.readInt();
+ int[] val = new int[len];
+ for (int j = 0; j < len; j++) {
+ val[j] = buffer.readInt();
+ }
+ intMap.put(name, val);
+ }
+ }
+ int bitmapMapSize = (sizes >> 16) & 0xFF;
+
+ if (bitmapMapSize > 0) {
+ bitmapMap = new HashMap<>();
+ for (int i = 0; i < bitmapMapSize; i++) {
+ String name = buffer.readUTF8();
+ int val = buffer.readInt();
+ bitmapMap.put(name, val);
+ }
+ }
+ operations.add(new ShaderData(shaderID, shaderTextId,
+ floatMap, intMap, bitmapMap));
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ context.loadShader(mShaderID, this);
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
index 5b622ae..ed13449 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
@@ -44,11 +44,13 @@
@Override
public String toString() {
- return "TEXT DATA " + mTextId + "\"" + mText + "\"";
+ return "TextData[" + mTextId + "] = \""
+ + Utils.trimString(mText, 10) + "\"";
}
public static class Companion implements CompanionOperation {
- private Companion() {}
+ private Companion() {
+ }
@Override
public String name() {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
new file mode 100644
index 0000000..65a39a1e
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.operations.utilities.StringUtils;
+
+import java.util.List;
+
+/**
+ * Operation convert floats to text
+ * This command is structured [command][textID][before,after][flags]
+ * before and after define number of digits before and after the decimal point
+ */
+public class TextFromFloat implements Operation, VariableSupport {
+ public int mTextId;
+ public float mValue;
+ public float mOutValue;
+ public short mDigitsBefore;
+ public short mDigitsAfter;
+ public int mFlags;
+ public static final Companion COMPANION = new Companion();
+ public static final int MAX_STRING_SIZE = 4000;
+ char mPre = ' ';
+ char mAfter = ' ';
+ // Theses flags define what how to/if fill the space
+ public static final int PAD_AFTER_SPACE = 0; // pad past point with space
+ public static final int PAD_AFTER_NONE = 1; // do not pad past last digit
+ public static final int PAD_AFTER_ZERO = 3; // pad with 0 past last digit
+ public static final int PAD_PRE_SPACE = 0; // pad before number with spaces
+ public static final int PAD_PRE_NONE = 4; // pad before number with 0s
+ public static final int PAD_PRE_ZERO = 12; // do not pad before number
+
+ public TextFromFloat(int textId, float value, short digitsBefore,
+ short digitsAfter, int flags) {
+ this.mTextId = textId;
+ this.mValue = value;
+ this.mDigitsAfter = digitsAfter;
+ this.mDigitsBefore = digitsBefore;
+ this.mFlags = flags;
+ mOutValue = mValue;
+ switch (mFlags & 3) {
+ case PAD_AFTER_SPACE:
+ mAfter = ' ';
+ break;
+ case PAD_AFTER_NONE:
+ mAfter = 0;
+ break;
+ case PAD_AFTER_ZERO:
+ mAfter = '0';
+ break;
+ }
+ switch (mFlags & 12) {
+ case PAD_PRE_SPACE:
+ mPre = ' ';
+ break;
+ case PAD_PRE_NONE:
+ mPre = 0;
+ break;
+ case PAD_PRE_ZERO:
+ mPre = '0';
+ break;
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mTextId, mValue, mDigitsAfter, mDigitsBefore, mFlags);
+ }
+
+ @Override
+ public String toString() {
+ return "TextFromFloat[" + mTextId + "] = "
+ + Utils.floatToString(mValue) + " " + mDigitsBefore
+ + "." + mDigitsAfter + " " + mFlags;
+ }
+
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ if (Float.isNaN(mValue)) {
+ mOutValue = context.getFloat(Utils.idFromNan(mValue));
+ }
+
+ }
+
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mValue)) {
+ context.listensTo(Utils.idFromNan(mValue), this);
+ }
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "TextData";
+ }
+
+ @Override
+ public int id() {
+ return Operations.TEXT_FROM_FLOAT;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param textId
+ * @param value
+ * @param digitsBefore
+ * @param digitsAfter
+ * @param flags
+ */
+ public void apply(WireBuffer buffer, int textId,
+ float value, short digitsBefore,
+ short digitsAfter, int flags) {
+ buffer.start(Operations.TEXT_FROM_FLOAT);
+ buffer.writeInt(textId);
+ buffer.writeFloat(value);
+ buffer.writeInt((digitsBefore << 16) | digitsAfter);
+ buffer.writeInt(flags);
+
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int textId = buffer.readInt();
+ float value = buffer.readFloat();
+ int tmp = buffer.readInt();
+ short post = (short) (tmp & 0xFFFF);
+ short pre = (short) ((tmp >> 16) & 0xFFFF);
+
+ int flags = buffer.readInt();
+ operations.add(new TextFromFloat(textId, value, pre, post, flags));
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ float v = mOutValue;
+ String s = StringUtils.floatToString(v, mDigitsBefore,
+ mDigitsAfter, mPre, mAfter);
+ context.loadText(mTextId, s);
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
new file mode 100644
index 0000000..a0fc854
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Operation to deal with Text data
+ */
+public class TextMerge implements Operation {
+ public int mTextId;
+ public int mSrcId1;
+ public int mSrcId2;
+ public static final Companion COMPANION = new Companion();
+ public static final int MAX_STRING_SIZE = 4000;
+
+ public TextMerge(int textId, int srcId1, int srcId2) {
+ this.mTextId = textId;
+ this.mSrcId1 = srcId1;
+ this.mSrcId2 = srcId2;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mTextId, mSrcId1, mSrcId2);
+ }
+
+ @Override
+ public String toString() {
+ return "TextMerge[" + mTextId + "] = [" + mSrcId1 + " ] + [ " + mSrcId2 + "]";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "TextData";
+ }
+
+ @Override
+ public int id() {
+ return Operations.TEXT_MERGE;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param textId
+ * @param srcId1
+ * @param srcId2
+ */
+ public void apply(WireBuffer buffer, int textId, int srcId1, int srcId2) {
+ buffer.start(Operations.TEXT_MERGE);
+ buffer.writeInt(textId);
+ buffer.writeInt(srcId1);
+ buffer.writeInt(srcId2);
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int textId = buffer.readInt();
+ int srcId1 = buffer.readInt();
+ int srcId2 = buffer.readInt();
+
+ operations.add(new TextMerge(textId, srcId1, srcId2));
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ String str1 = context.getText(mSrcId1);
+ String str2 = context.getText(mSrcId2);
+ context.loadText(mTextId, str1 + str2);
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
index 00e2f20..fdc6860 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
@@ -15,13 +15,16 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
+/**
+ * Utilities to be used across all core operations
+ */
public class Utils {
public static float asNan(int v) {
return Float.intBitsToFloat(v | -0x800000);
}
public static int idFromNan(float value) {
- int b = Float.floatToRawIntBits(value);
+ int b = Float.floatToRawIntBits(value);
return b & 0xFFFFF;
}
@@ -29,13 +32,194 @@
return 0;
}
- String getFloatString(float value) {
- if (Float.isNaN(value)) {
- int id = idFromNan(value);
- if (id > 0) {
- return "NaN(" + id + ")";
- }
+ /**
+ * trim a string to n characters if needing to trim
+ * end in "..."
+ *
+ * @param str
+ * @param n
+ * @return
+ */
+ static String trimString(String str, int n) {
+ if (str.length() > n) {
+ str = str.substring(0, n - 3) + "...";
}
- return "" + value;
+ return str;
}
+
+ /**
+ * print the id and the value of a float
+ * @param idvalue
+ * @param value
+ * @return
+ */
+ public static String floatToString(float idvalue, float value) {
+ if (Float.isNaN(idvalue)) {
+ return "[" + idFromNan(idvalue) + "]" + floatToString(value);
+ }
+ return floatToString(value);
+ }
+
+ /**
+ * Convert float to string but render nan id in brackets [n]
+ * @param value
+ * @return
+ */
+ public static String floatToString(float value) {
+ if (Float.isNaN(value)) {
+ return "[" + idFromNan(value) + "]";
+ }
+ return Float.toString(value);
+ }
+
+ /**
+ * Debugging util to print a message and include the file/line it came from
+ * @param str
+ */
+ public static void log(String str) {
+ StackTraceElement s = new Throwable().getStackTrace()[1];
+ System.out.println("(" + s.getFileName() + ":" + s.getLineNumber() + ")." + str);
+ }
+
+ /**
+ * Debugging util to print the stack
+ * @param str
+ * @param n
+ */
+ public static void logStack(String str, int n) {
+ StackTraceElement[] st = new Throwable().getStackTrace();
+ for (int i = 1; i < n + 1; i++) {
+ StackTraceElement s = st[i];
+ String space = new String(new char[i]).replace('\0', ' ');
+ System.out.println(space + "(" + s.getFileName()
+ + ":" + s.getLineNumber() + ")." + str);
+ }
+ }
+
+ /**
+ * Is a variable Allowed int calculation and references.
+ *
+ * @param v
+ * @return
+ */
+ public static boolean isVariable(float v) {
+ if (Float.isNaN(v)) {
+ int id = idFromNan(v);
+ return id > 40 || id < 10;
+ }
+ return false;
+ }
+
+ /**
+ * print a color in the familiar 0xAARRGGBB pattern
+ *
+ * @param color
+ * @return
+ */
+ public static String colorInt(int color) {
+ String str = "000000000000" + Integer.toHexString(color);
+ return "0x" + str.substring(str.length() - 8);
+ }
+
+ /**
+ * Interpolate two colors.
+ * gamma corrected colors are interpolated in the form c1 * (1-t) + c2 * t
+ *
+ * @param c1
+ * @param c2
+ * @param t
+ * @return
+ */
+ public static int interpolateColor(int c1, int c2, float t) {
+ if (Float.isNaN(t) || t == 0.0f) {
+ return c1;
+ } else if (t == 1.0f) {
+ return c2;
+ }
+ int a = 0xFF & (c1 >> 24);
+ int r = 0xFF & (c1 >> 16);
+ int g = 0xFF & (c1 >> 8);
+ int b = 0xFF & c1;
+ float f_r = (float) Math.pow(r / 255.0f, 2.2);
+ float f_g = (float) Math.pow(g / 255.0f, 2.2);
+ float f_b = (float) Math.pow(b / 255.0f, 2.2);
+ float c1fr = f_r;
+ float c1fg = f_g;
+ float c1fb = f_b;
+ float c1fa = a / 255f;
+
+ a = 0xFF & (c2 >> 24);
+ r = 0xFF & (c2 >> 16);
+ g = 0xFF & (c2 >> 8);
+ b = 0xFF & c2;
+ f_r = (float) Math.pow(r / 255.0f, 2.2);
+ f_g = (float) Math.pow(g / 255.0f, 2.2);
+ f_b = (float) Math.pow(b / 255.0f, 2.2);
+ float c2fr = f_r;
+ float c2fg = f_g;
+ float c2fb = f_b;
+ float c2fa = a / 255f;
+ f_r = c1fr + t * (c2fr - c1fr);
+ f_g = c1fg + t * (c2fg - c1fg);
+ f_b = c1fb + t * (c2fb - c1fb);
+ float f_a = c1fa + t * (c2fa - c1fa);
+
+ int outr = clamp((int) ((float) Math.pow(f_r, 1.0 / 2.2) * 255.0f));
+ int outg = clamp((int) ((float) Math.pow(f_g, 1.0 / 2.2) * 255.0f));
+ int outb = clamp((int) ((float) Math.pow(f_b, 1.0 / 2.2) * 255.0f));
+ int outa = clamp((int) (f_a * 255.0f));
+
+
+ return (outa << 24 | outr << 16 | outg << 8 | outb);
+ }
+
+ /**
+ * Efficient clamping function
+ *
+ * @param c
+ * @return number between 0 and 255
+ */
+ public static int clamp(int c) {
+ int n = 255;
+ c &= ~(c >> 31);
+ c -= n;
+ c &= (c >> 31);
+ c += n;
+ return c;
+ }
+
+ /**
+ * convert hue saturation and value to RGB
+ *
+ * @param hue 0..1
+ * @param saturation 0..1 0=on the gray scale
+ * @param value 0..1 0=black
+ * @return
+ */
+ public static int hsvToRgb(float hue, float saturation, float value) {
+ int h = (int) (hue * 6);
+ float f = hue * 6 - h;
+ int p = (int) (0.5f + 255 * value * (1 - saturation));
+ int q = (int) (0.5f + 255 * value * (1 - f * saturation));
+ int t = (int) (0.5f + 255 * value * (1 - (1 - f) * saturation));
+ int v = (int) (0.5f + 255 * value);
+ switch (h) {
+ case 0:
+ return 0XFF000000 | (v << 16) + (t << 8) + p;
+ case 1:
+ return 0XFF000000 | (q << 16) + (v << 8) + p;
+ case 2:
+ return 0XFF000000 | (p << 16) + (v << 8) + t;
+ case 3:
+ return 0XFF000000 | (p << 16) + (q << 8) + v;
+ case 4:
+ return 0XFF000000 | (t << 16) + (p << 8) + v;
+ case 5:
+ return 0XFF000000 | (v << 16) + (p << 8) + q;
+
+ }
+ return 0;
+ }
+
+
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
index 8abb0bf..a7d0ac6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
@@ -15,43 +15,60 @@
*/
package com.android.internal.widget.remotecompose.core.operations.paint;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
import java.util.Arrays;
+/**
+ * Paint Bundle represents a delta of changes to a paint object
+ */
public class PaintBundle {
int[] mArray = new int[200];
+ int[] mOutArray = null;
int mPos = 0;
- public void applyPaintChange(PaintChanges p) {
+ /**
+ * Apply changes to a PaintChanges interface
+ * @param paintContext
+ * @param p
+ */
+ public void applyPaintChange(PaintContext paintContext, PaintChanges p) {
int i = 0;
int mask = 0;
+ if (mOutArray == null) {
+ mOutArray = mArray;
+ }
while (i < mPos) {
- int cmd = mArray[i++];
+ int cmd = mOutArray[i++];
mask = mask | (1 << (cmd - 1));
switch (cmd & 0xFFFF) {
case TEXT_SIZE: {
- p.setTextSize(Float.intBitsToFloat(mArray[i++]));
+ p.setTextSize(Float.intBitsToFloat(mOutArray[i++]));
break;
}
case TYPEFACE:
int style = (cmd >> 16);
int weight = style & 0x3ff;
boolean italic = (style >> 10) > 0;
- int font_type = mArray[i++];
+ int font_type = mOutArray[i++];
p.setTypeFace(font_type, weight, italic);
break;
+ case COLOR_ID: // mOutArray should have already decoded it
case COLOR: {
- p.setColor(mArray[i++]);
+ p.setColor(mOutArray[i++]);
break;
}
case STROKE_WIDTH: {
- p.setStrokeWidth(Float.intBitsToFloat(mArray[i++]));
+ p.setStrokeWidth(Float.intBitsToFloat(mOutArray[i++]));
break;
}
case STROKE_MITER: {
- p.setStrokeMiter(Float.intBitsToFloat(mArray[i++]));
+ p.setStrokeMiter(Float.intBitsToFloat(mOutArray[i++]));
break;
}
case STROKE_CAP: {
@@ -63,6 +80,7 @@
break;
}
case SHADER: {
+ p.setShader(mOutArray[i++]);
break;
}
case STROKE_JOIN: {
@@ -81,17 +99,16 @@
p.setFilterBitmap(!((cmd >> 16) == 0));
break;
}
-
case GRADIENT: {
- i = callSetGradient(cmd, mArray, i, p);
+ i = callSetGradient(cmd, mOutArray, i, p);
break;
}
case COLOR_FILTER: {
- p.setColorFilter(mArray[i++], cmd >> 16);
+ p.setColorFilter(mOutArray[i++], cmd >> 16);
break;
}
case ALPHA: {
- p.setAlpha(Float.intBitsToFloat(mArray[i++]));
+ p.setAlpha(Float.intBitsToFloat(mOutArray[i++]));
break;
}
}
@@ -106,7 +123,6 @@
switch (id) {
case TEXT_SIZE:
return "TEXT_SIZE";
-
case COLOR:
return "COLOR";
case STROKE_WIDTH:
@@ -133,7 +149,6 @@
return "ALPHA";
case COLOR_FILTER:
return "COLOR_FILTER";
-
}
return "????" + id + "????";
}
@@ -154,6 +169,14 @@
return str + "]";
}
+ private static String asFloatStr(int value) {
+ float fValue = Float.intBitsToFloat(value);
+ if (Float.isNaN(fValue)) {
+ return "[" + Utils.idFromNan(fValue) + "]";
+ }
+ return Float.toString(fValue);
+ }
+
@Override
public String toString() {
StringBuilder ret = new StringBuilder("\n");
@@ -164,7 +187,8 @@
switch (type) {
case TEXT_SIZE: {
- ret.append(" TextSize(" + Float.intBitsToFloat(mArray[i++]));
+ ret.append(" TextSize("
+ + asFloatStr(mArray[i++]));
}
break;
@@ -181,14 +205,18 @@
ret.append(" Color(" + colorInt(mArray[i++]));
}
break;
+ case COLOR_ID: {
+ ret.append(" ColorId([" + mArray[i++] + "]");
+ }
+ break;
case STROKE_WIDTH: {
ret.append(" StrokeWidth("
- + (Float.intBitsToFloat(mArray[i++])));
+ + (asFloatStr(mArray[i++])));
}
break;
case STROKE_MITER: {
ret.append(" StrokeMiter("
- + (Float.intBitsToFloat(mArray[i++])));
+ + (asFloatStr(mArray[i++])));
}
break;
case STROKE_CAP: {
@@ -207,11 +235,12 @@
}
break;
case SHADER: {
+ ret.append(" Shader(" + mArray[i++]);
}
break;
case ALPHA: {
ret.append(" Alpha("
- + (Float.intBitsToFloat(mArray[i++])));
+ + (asFloatStr(mArray[i++])));
}
break;
case IMAGE_FILTER_QUALITY: {
@@ -244,7 +273,6 @@
return ret.toString();
}
-
int callPrintGradient(int cmd, int[] array, int i, StringBuilder p) {
int ret = i;
int type = (cmd >> 16);
@@ -258,26 +286,25 @@
colors = new int[len];
for (int j = 0; j < colors.length; j++) {
colors[j] = array[ret++];
-
}
}
len = array[ret++];
- float[] stops = null;
+ String[] stops = null;
if (len > 0) {
- stops = new float[len];
+ stops = new String[len];
for (int j = 0; j < stops.length; j++) {
- stops[j] = Float.intBitsToFloat(array[ret++]);
+ stops[j] = asFloatStr(array[ret++]);
}
}
p.append(" colors = " + colorInt(colors) + ",\n");
p.append(" stops = " + Arrays.toString(stops) + ",\n");
p.append(" start = ");
- p.append("[" + Float.intBitsToFloat(array[ret++]));
- p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n");
+ p.append("[" + asFloatStr(array[ret++]));
+ p.append(", " + asFloatStr(array[ret++]) + "],\n");
p.append(" end = ");
- p.append("[" + Float.intBitsToFloat(array[ret++]));
- p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n");
+ p.append("[" + asFloatStr(array[ret++]));
+ p.append(", " + asFloatStr(array[ret++]) + "],\n");
int tileMode = array[ret++];
p.append(" tileMode = " + tileMode + "\n ");
}
@@ -295,21 +322,21 @@
}
}
len = array[ret++];
- float[] stops = null;
+ String[] stops = null;
if (len > 0) {
- stops = new float[len];
+ stops = new String[len];
for (int j = 0; j < stops.length; j++) {
- stops[j] = Float.intBitsToFloat(array[ret++]);
+ stops[j] = asFloatStr(array[ret++]);
}
}
p.append(" colors = " + colorInt(colors) + ",\n");
p.append(" stops = " + Arrays.toString(stops) + ",\n");
p.append(" center = ");
- p.append("[" + Float.intBitsToFloat(array[ret++]));
- p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n");
+ p.append("[" + asFloatStr(array[ret++]));
+ p.append(", " + asFloatStr(array[ret++]) + "],\n");
p.append(" radius =");
- p.append(" " + Float.intBitsToFloat(array[ret++]) + ",\n");
+ p.append(" " + asFloatStr(array[ret++]) + ",\n");
int tileMode = array[ret++];
p.append(" tileMode = " + tileMode + "\n ");
}
@@ -327,20 +354,19 @@
}
}
len = array[ret++];
- float[] stops = null;
+ String[] stops = null;
if (len > 0) {
- stops = new float[len];
+ stops = new String[len];
for (int j = 0; j < stops.length; j++) {
- stops[j] = Float.intBitsToFloat(array[ret++]);
+ stops[j] = asFloatStr(array[ret++]);
}
}
-
p.append(" colors = " + colorInt(colors) + ",\n");
p.append(" stops = " + Arrays.toString(stops) + ",\n");
p.append(" center = ");
- p.append("[" + Float.intBitsToFloat(array[ret++]));
- p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n ");
-
+ p.append("[" + asFloatStr(array[ret++]));
+ p.append(", "
+ + asFloatStr(array[ret++]) + "],\n ");
}
break;
default: {
@@ -376,7 +402,6 @@
return ret;
}
-
switch (gradientType) {
case LINEAR_GRADIENT: {
@@ -433,7 +458,7 @@
public static final int COLOR = 4; // int
public static final int STROKE_WIDTH = 5; // float
public static final int STROKE_MITER = 6;
- public static final int STROKE_CAP = 7; // int
+ public static final int STROKE_CAP = 7; // int
public static final int STYLE = 8; // int
public static final int SHADER = 9; // int
public static final int IMAGE_FILTER_QUALITY = 10; // int
@@ -445,7 +470,7 @@
public static final int TYPEFACE = 16;
public static final int FILTER_BITMAP = 17;
public static final int BLEND_MODE = 18;
-
+ public static final int COLOR_ID = 19; // int
public static final int BLEND_MODE_CLEAR = 0;
public static final int BLEND_MODE_SRC = 1;
@@ -634,8 +659,8 @@
/**
* @param fontType 0 = default 1 = sans serif 2 = serif 3 = monospace
- * @param weight 100-1000
- * @param italic tur
+ * @param weight 100-1000
+ * @param italic tur
*/
public void setTextStyle(int fontType, int weight, boolean italic) {
int style = (weight & 0x3FF) | (italic ? 2048 : 0); // pack the weight and italic
@@ -658,6 +683,10 @@
mPos++;
}
+ /**
+ * Set the Color based on Color
+ * @param color
+ */
public void setColor(int color) {
mArray[mPos] = COLOR;
mPos++;
@@ -666,6 +695,18 @@
}
/**
+ * Set the Color based on ID
+ * @param color
+ */
+ public void setColorId(int color) {
+ mArray[mPos] = COLOR_ID;
+ mPos++;
+ mArray[mPos] = color;
+ mPos++;
+ }
+
+
+ /**
* Set the paint's Cap.
*
* @param cap set the paint's line cap style, used whenever the paint's
@@ -676,16 +717,29 @@
mPos++;
}
+ /**
+ * Set the style STROKE and/or FILL
+ * @param style
+ */
public void setStyle(int style) {
mArray[mPos] = STYLE | (style << 16);
mPos++;
}
- public void setShader(int shader, String shaderString) {
- mArray[mPos] = SHADER | (shader << 16);
+ /**
+ * Set the shader id to use
+ * @param shaderId
+ */
+ public void setShader(int shaderId) {
+ mArray[mPos] = SHADER;
+ mPos++;
+ mArray[mPos] = shaderId;
mPos++;
}
+ /**
+ * Set the Alpha value
+ */
public void setAlpha(float alpha) {
mArray[mPos] = ALPHA;
mPos++;
@@ -729,7 +783,6 @@
* destination pixels
* (content of the render target).
*
- *
* @param blendmode The blend mode to be installed in the paint
*/
public void setBlendMode(int blendmode) {
@@ -825,5 +878,216 @@
return "null";
}
-}
+ /**
+ * Check all the floats for Nan(id) floats and call listenTo
+ * @param context
+ * @param support
+ */
+ public void registerVars(RemoteContext context, VariableSupport support) {
+ int i = 0;
+ while (i < mPos) {
+ int cmd = mArray[i++];
+ int type = cmd & 0xFFFF;
+ switch (type) {
+ case STROKE_MITER:
+ case STROKE_WIDTH:
+ case ALPHA:
+ case TEXT_SIZE:
+ float v = Float.intBitsToFloat(mArray[i++]);
+ if (Float.isNaN(v)) {
+ context.listensTo(Utils.idFromNan(v), support);
+ }
+ break;
+ case COLOR_ID:
+ context.listensTo(mArray[i++], support);
+ break;
+ case COLOR:
+ case TYPEFACE:
+ case SHADER:
+ case COLOR_FILTER:
+ i++;
+ break;
+ case STROKE_JOIN:
+ case FILTER_BITMAP:
+ case STROKE_CAP:
+ case STYLE:
+ case IMAGE_FILTER_QUALITY:
+ case BLEND_MODE:
+ case ANTI_ALIAS:
+ break;
+
+ case GRADIENT: {
+ // TODO gradients should be handled correctly
+ i = callPrintGradient(cmd, mArray, i, new StringBuilder());
+ }
+ }
+ }
+ }
+
+ /**
+ * Update variables if any are float ids
+ * @param context
+ */
+ public void updateVariables(RemoteContext context) {
+ if (mOutArray == null) {
+ mOutArray = Arrays.copyOf(mArray, mArray.length);
+ } else {
+ System.arraycopy(mArray, 0, mOutArray, 0, mArray.length);
+ }
+ int i = 0;
+ while (i < mPos) {
+ int cmd = mArray[i++];
+ int type = cmd & 0xFFFF;
+ switch (type) {
+ case STROKE_MITER:
+ case STROKE_WIDTH:
+ case ALPHA:
+ case TEXT_SIZE:
+ mOutArray[i] = fixFloatVar(mArray[i], context);
+ i++;
+ break;
+ case COLOR_ID:
+ mOutArray[i] = fixColor(mArray[i], context);
+ i++;
+ break;
+ case COLOR:
+ case TYPEFACE:
+ case SHADER:
+ case COLOR_FILTER:
+ i++;
+ break;
+ case STROKE_JOIN:
+ case FILTER_BITMAP:
+ case STROKE_CAP:
+ case STYLE:
+ case IMAGE_FILTER_QUALITY:
+ case BLEND_MODE:
+ case ANTI_ALIAS:
+ break;
+
+ case GRADIENT: {
+ // TODO gradients should be handled correctly
+ i = updateFloatsInGradient(cmd, mOutArray, mArray, i, context);
+ }
+ }
+ }
+ }
+
+ private int fixFloatVar(int val, RemoteContext context) {
+ float v = Float.intBitsToFloat(val);
+ if (Float.isNaN(v)) {
+ int id = Utils.idFromNan(v);
+ return Float.floatToRawIntBits(context.getFloat(id));
+ }
+ return val;
+ }
+
+ private int fixColor(int colorId, RemoteContext context) {
+ int n = context.getColor(colorId);
+ return n;
+ }
+
+ int updateFloatsInGradient(int cmd, int[] out, int[] array,
+ int i,
+ RemoteContext context) {
+ int ret = i;
+ int type = (cmd >> 16);
+ switch (type) {
+ case 0: {
+ int len = array[ret++];
+ if (len > 0) {
+ for (int j = 0; j < len; j++) {
+ ret++;
+ }
+ }
+ len = array[ret++];
+
+ if (len > 0) {
+ for (int j = 0; j < len; j++) {
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ }
+ }
+
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+
+ // end
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ ret++; // tileMode
+ }
+
+ break;
+ case 1: {
+ // RadialGradient
+ int len = array[ret++];
+ if (len > 0) {
+ for (int j = 0; j < len; j++) {
+ ret++;
+ }
+ }
+ len = array[ret++];
+ if (len > 0) {
+ for (int j = 0; j < len; j++) {
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ }
+ }
+
+
+ // center
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ // radius
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ ret++; // tileMode
+
+ }
+
+ break;
+ case 2: {
+ // SweepGradient
+ int len = array[ret++];
+ int[] colors = null;
+ if (len > 0) {
+ colors = new int[len];
+ for (int j = 0; j < colors.length; j++) {
+ colors[j] = array[ret++];
+
+ }
+ }
+ len = array[ret++];
+ float[] stops = null;
+ if (len > 0) {
+ stops = new float[len];
+ for (int j = 0; j < stops.length; j++) {
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ }
+ }
+
+ // center
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ }
+ break;
+ default: {
+ System.err.println("gradient type unknown");
+ }
+ }
+
+ return ret;
+ }
+
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
index 994bf6d..28fe63a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
@@ -27,7 +27,6 @@
}
-
@Override
public void setStrokeWidth(float width) {
@@ -49,7 +48,7 @@
}
@Override
- public void setShader(int shader, String shaderString) {
+ public void setShader(int shader) {
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
index 87e58ac..d5dc388 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
@@ -15,9 +15,14 @@
*/
package com.android.internal.widget.remotecompose.core.operations.paint;
+/**
+ * Interface to a paint object
+ * For more details see Android Paint
+ */
public interface PaintChanges {
-
+ // MASK to be set/cleared
+ int CLEAR_TEXT_SIZE = 1 << (PaintBundle.TEXT_SIZE - 1);
int CLEAR_TEXT_STYLE = 1 << (PaintBundle.TYPEFACE - 1);
int CLEAR_COLOR = 1 << (PaintBundle.COLOR - 1);
int CLEAR_STROKE_WIDTH = 1 << (PaintBundle.STROKE_WIDTH - 1);
@@ -32,21 +37,101 @@
int CLEAR_COLOR_FILTER = 1 << (PaintBundle.COLOR_FILTER - 1);
int VALID_BITS = 0x1FFF; // only the first 13 bit are valid now
-
+ /**
+ * Set the size of text
+ * @param size
+ */
void setTextSize(float size);
+
+ /**
+ * Set the width of lines
+ * @param width
+ */
void setStrokeWidth(float width);
+
+ /**
+ * Set the color to use
+ * @param color
+ */
void setColor(int color);
+
+ /**
+ * Set the Stroke Cap
+ * @param cap
+ */
void setStrokeCap(int cap);
+
+ /**
+ * Set the Stroke style FILL and/or STROKE
+ * @param style
+ */
void setStyle(int style);
- void setShader(int shader, String shaderString);
+
+ /**
+ * Set the id of the shader to use
+ * @param shader
+ */
+ void setShader(int shader);
+
+ /**
+ * Set the way image is interpolated
+ * @param quality
+ */
void setImageFilterQuality(int quality);
+
+ /**
+ * Set the alpha to draw under
+ * @param a
+ */
void setAlpha(float a);
+
+ /**
+ * Set the Stroke Miter
+ * @param miter
+ */
void setStrokeMiter(float miter);
+
+ /**
+ * Set the Stroke Join
+ * @param join
+ */
void setStrokeJoin(int join);
+
+ /**
+ * Should bitmaps be interpolated
+ * @param filter
+ */
void setFilterBitmap(boolean filter);
+
+ /**
+ * Set the blend mode can be porterduff + others
+ * @param mode
+ */
void setBlendMode(int mode);
+
+ /**
+ * Set the AntiAlias. Typically true
+ * Set to off when you need pixilated look (e.g. QR codes)
+ * @param aa
+ */
void setAntiAlias(boolean aa);
+
+ /**
+ * Clear some sub set of the settings
+ * @param mask
+ */
void clear(long mask);
+
+ /**
+ * Set a linear gradient fill
+ * @param colorsArray
+ * @param stopsArray
+ * @param startX
+ * @param startY
+ * @param endX
+ * @param endY
+ * @param tileMode
+ */
void setLinearGradient(
int[] colorsArray,
float[] stopsArray,
@@ -57,6 +142,15 @@
int tileMode
);
+ /**
+ * Set a radial gradient fill
+ * @param colorsArray
+ * @param stopsArray
+ * @param centerX
+ * @param centerY
+ * @param radius
+ * @param tileMode
+ */
void setRadialGradient(
int[] colorsArray,
float[] stopsArray,
@@ -66,6 +160,13 @@
int tileMode
);
+ /**
+ * Set a sweep gradient fill
+ * @param colorsArray
+ * @param stopsArray
+ * @param centerX
+ * @param centerY
+ */
void setSweepGradient(
int[] colorsArray,
float[] stopsArray,
@@ -73,9 +174,19 @@
float centerY
);
-
+ /**
+ * Set Color filter mod
+ * @param color
+ * @param mode
+ */
void setColorFilter(int color, int mode);
+ /**
+ * Set TypeFace 0,1,2
+ * TODO above should point to a string to be decoded
+ * @param fontType
+ * @param weight
+ * @param italic
+ */
void setTypeFace(int fontType, int weight, boolean italic);
-}
-
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
new file mode 100644
index 0000000..616048d
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities;
+
+/**
+ * high performance floating point expression evaluator used in animation
+ */
+public class AnimatedFloatExpression {
+ static IntMap<String> sNames = new IntMap<>();
+ public static final int OFFSET = 0x100;
+ public static final float ADD = asNan(OFFSET + 1);
+ public static final float SUB = asNan(OFFSET + 2);
+ public static final float MUL = asNan(OFFSET + 3);
+ public static final float DIV = asNan(OFFSET + 4);
+ public static final float MOD = asNan(OFFSET + 5);
+ public static final float MIN = asNan(OFFSET + 6);
+ public static final float MAX = asNan(OFFSET + 7);
+ public static final float POW = asNan(OFFSET + 8);
+ public static final float SQRT = asNan(OFFSET + 9);
+ public static final float ABS = asNan(OFFSET + 10);
+ public static final float SIGN = asNan(OFFSET + 11);
+ public static final float COPY_SIGN = asNan(OFFSET + 12);
+ public static final float EXP = asNan(OFFSET + 13);
+ public static final float FLOOR = asNan(OFFSET + 14);
+ public static final float LOG = asNan(OFFSET + 15);
+ public static final float LN = asNan(OFFSET + 16);
+ public static final float ROUND = asNan(OFFSET + 17);
+ public static final float SIN = asNan(OFFSET + 18);
+ public static final float COS = asNan(OFFSET + 19);
+ public static final float TAN = asNan(OFFSET + 20);
+ public static final float ASIN = asNan(OFFSET + 21);
+ public static final float ACOS = asNan(OFFSET + 22);
+
+ public static final float ATAN = asNan(OFFSET + 23);
+
+ public static final float ATAN2 = asNan(OFFSET + 24);
+ public static final float MAD = asNan(OFFSET + 25);
+ public static final float IFELSE = asNan(OFFSET + 26);
+
+ public static final float CLAMP = asNan(OFFSET + 27);
+ public static final float CBRT = asNan(OFFSET + 28);
+ public static final float DEG = asNan(OFFSET + 29);
+ public static final float RAD = asNan(OFFSET + 30);
+ public static final float CEIL = asNan(OFFSET + 31);
+
+
+ public static final float LAST_OP = 31;
+
+
+ public static final float VAR1 = asNan(OFFSET + 27);
+ public static final float VAR2 = asNan(OFFSET + 28);
+
+ // TODO CLAMP, CBRT, DEG, RAD, EXPM1, CEIL, FLOOR
+ private static final float FP_PI = (float) Math.PI;
+ private static final float FP_TO_RAD = 57.29577951f; // 180/PI
+ private static final float FP_TO_DEG = 0.01745329252f; // 180/PI
+
+ float[] mStack;
+ float[] mLocalStack = new float[128];
+ float[] mVar;
+
+ /**
+ * is float a math operator
+ * @param v
+ * @return
+ */
+ public static boolean isMathOperator(float v) {
+ if (Float.isNaN(v)) {
+ int pos = fromNaN(v);
+ return pos > OFFSET && pos <= OFFSET + LAST_OP;
+ }
+ return false;
+ }
+
+ interface Op {
+ int eval(int sp);
+ }
+
+ /**
+ * Evaluate a float expression
+ * @param exp
+ * @param var
+ * @return
+ */
+ public float eval(float[] exp, float... var) {
+ mStack = exp;
+ mVar = var;
+ int sp = -1;
+ for (int i = 0; i < mStack.length; i++) {
+ float v = mStack[i];
+ if (Float.isNaN(v)) {
+ sp = mOps[fromNaN(v) - OFFSET].eval(sp);
+ } else {
+ mStack[++sp] = v;
+ }
+ }
+ return mStack[sp];
+ }
+
+ /**
+ * Evaluate a float expression
+ * @param exp
+ * @param len
+ * @param var
+ * @return
+ */
+ public float eval(float[] exp, int len, float... var) {
+ System.arraycopy(exp, 0, mLocalStack, 0, len);
+ mStack = mLocalStack;
+ mVar = var;
+ int sp = -1;
+ for (int i = 0; i < len; i++) {
+ float v = mStack[i];
+ if (Float.isNaN(v)) {
+ sp = mOps[fromNaN(v) - OFFSET].eval(sp);
+ } else {
+ mStack[++sp] = v;
+ }
+ }
+ return mStack[sp];
+ }
+
+ /**
+ * Evaluate a float expression
+ * @param exp
+ * @param var
+ * @return
+ */
+ public float evalDB(float[] exp, float... var) {
+ mStack = exp;
+ mVar = var;
+ int sp = -1;
+ for (float v : exp) {
+ if (Float.isNaN(v)) {
+ System.out.print(" " + sNames.get((fromNaN(v) - OFFSET)));
+ sp = mOps[fromNaN(v) - OFFSET].eval(sp);
+ } else {
+ System.out.print(" " + v);
+ mStack[++sp] = v;
+ }
+ }
+ return mStack[sp];
+ }
+
+ Op[] mOps = {
+ null,
+ (sp) -> { // ADD
+ mStack[sp - 1] = mStack[sp - 1] + mStack[sp];
+ return sp - 1;
+ },
+ (sp) -> { // SUB
+ mStack[sp - 1] = mStack[sp - 1] - mStack[sp];
+ return sp - 1;
+ },
+ (sp) -> { // MUL
+ mStack[sp - 1] = mStack[sp - 1] * mStack[sp];
+ return sp - 1;
+ },
+ (sp) -> { // DIV
+ mStack[sp - 1] = mStack[sp - 1] / mStack[sp];
+ return sp - 1;
+ },
+ (sp) -> { // MOD
+ mStack[sp - 1] = mStack[sp - 1] % mStack[sp];
+ return sp - 1;
+ },
+ (sp) -> { // MIN
+ mStack[sp - 1] = (float) Math.min(mStack[sp - 1], mStack[sp]);
+ return sp - 1;
+ },
+ (sp) -> { // MAX
+ mStack[sp - 1] = (float) Math.max(mStack[sp - 1], mStack[sp]);
+ return sp - 1;
+ },
+ (sp) -> { // POW
+ mStack[sp - 1] = (float) Math.pow(mStack[sp - 1], mStack[sp]);
+ return sp - 1;
+ },
+ (sp) -> { // SQRT
+ mStack[sp] = (float) Math.sqrt(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ABS
+ mStack[sp] = (float) Math.abs(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // SIGN
+ mStack[sp] = (float) Math.signum(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // copySign
+ mStack[sp - 1] = (float) Math.copySign(mStack[sp - 1], mStack[sp]);
+ return sp - 1;
+ },
+ (sp) -> { // EXP
+ mStack[sp] = (float) Math.exp(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // FLOOR
+ mStack[sp] = (float) Math.floor(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // LOG
+ mStack[sp] = (float) Math.log10(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // LN
+ mStack[sp] = (float) Math.log(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ROUND
+ mStack[sp] = (float) Math.round(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // SIN
+ mStack[sp] = (float) Math.sin(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // COS
+ mStack[sp] = (float) Math.cos(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // TAN
+ mStack[sp] = (float) Math.tan(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ASIN
+ mStack[sp] = (float) Math.asin(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ACOS
+ mStack[sp] = (float) Math.acos(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ATAN
+ mStack[sp] = (float) Math.atan(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ATAN2
+ mStack[sp - 1] = (float) Math.atan2(mStack[sp - 1], mStack[sp]);
+ return sp - 1;
+ },
+ (sp) -> { // MAD
+ mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2];
+ return sp - 2;
+ },
+ (sp) -> { // Ternary conditional
+ mStack[sp - 2] = (mStack[sp] > 0)
+ ? mStack[sp - 1] : mStack[sp - 2];
+ return sp - 2;
+ },
+ (sp) -> { // CLAMP(min,max, val)
+ mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]),
+ mStack[sp - 1]);
+ return sp - 2;
+ },
+ (sp) -> { // CBRT cuberoot
+ mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.);
+ return sp;
+ },
+ (sp) -> { // DEG
+ mStack[sp] = mStack[sp] * FP_TO_RAD;
+ return sp;
+ },
+ (sp) -> { // RAD
+ mStack[sp] = mStack[sp] * FP_TO_DEG;
+ return sp;
+ },
+ (sp) -> { // CEIL
+ mStack[sp] = (float) Math.ceil(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // first var =
+ mStack[sp] = mVar[0];
+ return sp;
+ },
+ (sp) -> { // second var y?
+ mStack[sp] = mVar[1];
+ return sp;
+ },
+ (sp) -> { // 3rd var z?
+ mStack[sp] = mVar[2];
+ return sp;
+ },
+ };
+
+ static {
+ int k = 0;
+ sNames.put(k++, "NOP");
+ sNames.put(k++, "+");
+ sNames.put(k++, "-");
+ sNames.put(k++, "*");
+ sNames.put(k++, "/");
+ sNames.put(k++, "%");
+ sNames.put(k++, "min");
+ sNames.put(k++, "max");
+ sNames.put(k++, "pow");
+ sNames.put(k++, "sqrt");
+ sNames.put(k++, "abs");
+ sNames.put(k++, "sign");
+ sNames.put(k++, "copySign");
+ sNames.put(k++, "exp");
+ sNames.put(k++, "floor");
+ sNames.put(k++, "log");
+ sNames.put(k++, "ln");
+ sNames.put(k++, "round");
+ sNames.put(k++, "sin");
+ sNames.put(k++, "cos");
+ sNames.put(k++, "tan");
+ sNames.put(k++, "asin");
+ sNames.put(k++, "acos");
+ sNames.put(k++, "atan");
+ sNames.put(k++, "atan2");
+ sNames.put(k++, "mad");
+ sNames.put(k++, "ifElse");
+ sNames.put(k++, "clamp");
+ sNames.put(k++, "cbrt");
+ sNames.put(k++, "deg");
+ sNames.put(k++, "rad");
+ sNames.put(k++, "ceil");
+ sNames.put(k++, "a[0]");
+ sNames.put(k++, "a[1]");
+ sNames.put(k++, "a[2]");
+ }
+
+ /**
+ * given a float command return its math name (e.g sin, cos etc.)
+ * @param f
+ * @return
+ */
+ public static String toMathName(float f) {
+ int id = fromNaN(f) - OFFSET;
+ return sNames.get(id);
+ }
+
+ /**
+ * Convert an expression encoded as an array of floats int ot a string
+ * @param exp
+ * @param labels
+ * @return
+ */
+ public static String toString(float[] exp, String[] labels) {
+ StringBuilder s = new StringBuilder();
+ for (int i = 0; i < exp.length; i++) {
+ float v = exp[i];
+ if (Float.isNaN(v)) {
+ if (isMathOperator(v)) {
+ s.append(toMathName(v));
+ } else {
+ s.append("[");
+ s.append(fromNaN(v));
+ s.append("]");
+ }
+ } else {
+ if (labels[i] != null) {
+ s.append(labels[i]);
+ }
+ s.append(v);
+ }
+ s.append(" ");
+ }
+ return s.toString();
+ }
+
+ static String toString(float[] exp, int sp) {
+ String[] str = new String[exp.length];
+ if (Float.isNaN(exp[sp])) {
+ int id = fromNaN(exp[sp]) - OFFSET;
+ switch (NO_OF_OPS[id]) {
+ case -1:
+ return "nop";
+ case 1:
+ return sNames.get(id) + "(" + toString(exp, sp + 1) + ") ";
+ case 2:
+ if (infix(id)) {
+ return "(" + toString(exp, sp + 1)
+ + sNames.get(id) + " "
+ + toString(exp, sp + 2) + ") ";
+ } else {
+ return sNames.get(id) + "("
+ + toString(exp, sp + 1) + ", "
+ + toString(exp, sp + 2) + ")";
+ }
+ case 3:
+ if (infix(id)) {
+ return "((" + toString(exp, sp + 1) + ") ? "
+ + toString(exp, sp + 2) + ":"
+ + toString(exp, sp + 3) + ")";
+ } else {
+ return sNames.get(id)
+ + "(" + toString(exp, sp + 1)
+ + ", " + toString(exp, sp + 2)
+ + ", " + toString(exp, sp + 3) + ")";
+ }
+ }
+ }
+ return Float.toString(exp[sp]);
+ }
+
+ static final int[] NO_OF_OPS = {
+ -1, // no op
+ 2, 2, 2, 2, 2, // + - * / %
+ 2, 2, 2, // min max, power
+ 1, 1, 1, 1, 1, 1, 1, 1, //sqrt,abs,CopySign,exp,floor,log,ln
+ 1, 1, 1, 1, 1, 1, 1, 2, // round,sin,cos,tan,asin,acos,atan,atan2
+ 3, 3, 3, 1, 1, 1, 1,
+ 0, 0, 0 // mad, ?:,
+ // a[0],a[1],a[2]
+ };
+
+ /**
+ * to be used by parser to determine if command is infix
+ * @param n
+ * @return
+ */
+ static boolean infix(int n) {
+ return ((n < 6) || (n == 25) || (n == 26));
+ }
+
+ /**
+ * Convert an id into a NaN object
+ * @param v
+ * @return
+ */
+ public static float asNan(int v) {
+ return Float.intBitsToFloat(v | -0x800000);
+ }
+
+ /**
+ * Get ID from a NaN float
+ * @param v
+ * @return
+ */
+ public static int fromNaN(float v) {
+ int b = Float.floatToRawIntBits(v);
+ return b & 0xFFFFF;
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ColorUtils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ColorUtils.java
new file mode 100644
index 0000000..0ea28a8
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ColorUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities;
+
+/**
+ * These are tools to use long Color as variables
+ * long colors are stored a 0xXXXXXXXX XXXXXX??
+ * in SRGB the colors are stored 0xAARRGGBB,00000000
+ * SRGB color sapce is color space 0
+ * Our Color will use color float with a
+ * Current android supports
+ * SRGB, LINEAR_SRGB, EXTENDED_SRGB, LINEAR_EXTENDED_SRGB, BT709, BT2020,
+ * DCI_P3, DISPLAY_P3, NTSC_1953, SMPTE_C, ADOBE_RGB, PRO_PHOTO_RGB, ACES,
+ * ACESCG, CIE_XYZ, CIE_LAB, BT2020_HLG, BT2020_PQ 0..17 respectively
+ *
+ * Our color space will be 62 (MAX_ID-1). (0x3E)
+ * Storing the default value in SRGB format and having the
+ * id of the color between the ARGB values and the 62 i.e.
+ * 0xAARRGGBB 00 00 00 3E
+ *
+ */
+public class ColorUtils {
+ public static int RC_COLOR = 62;
+
+ long packRCColor(int defaultARGB, int id) {
+ long l = defaultARGB;
+ return (l << 32) | id << 8 | RC_COLOR;
+ }
+
+ boolean isRCColor(long color) {
+ return ((color & 0x3F) == 62);
+ }
+
+ int getID(long color) {
+ if (isRCColor(color)) {
+ return (int) ((color & 0xFFFFFF00) >> 8);
+ }
+ return -1;
+ }
+
+ /**
+ * get default color from long color
+ * @param color
+ * @return
+ */
+ public int getDefaultColor(long color) {
+ if (isRCColor(color)) {
+ return (int) (color >> 32);
+ }
+ if (((color & 0xFF) == 0)) {
+ return (int) (color >> 32);
+ }
+ return 0;
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
index 8051ef1..0512fa6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
@@ -50,7 +50,6 @@
return insert(key, value);
}
-
public T get(int key) {
int index = findKey(key);
if (index == -1) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/NanMap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/NanMap.java
new file mode 100644
index 0000000..f4cd504
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/NanMap.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities;
+
+import com.android.internal.widget.remotecompose.core.operations.Utils;
+
+/**
+ * This defines the major id maps and ranges used by remote compose
+ * Generally ids ranging from 0 ... FFF (4095) are for ids
+ * 0x1000-0x1100 are used for path operations in PathData
+ * 0x1100-0x1200 are used for math operations in Animated float
+ * 0x
+ */
+public class NanMap {
+
+ public static final int MOVE = 0x1000;
+ public static final int LINE = 0x1001;
+ public static final int QUADRATIC = 0x1002;
+ public static final int CONIC = 0x1003;
+ public static final int CUBIC = 0x1004;
+ public static final int CLOSE = 0x1005;
+ public static final int DONE = 0x1006;
+ public static final float MOVE_NAN = Utils.asNan(MOVE);
+ public static final float LINE_NAN = Utils.asNan(LINE);
+ public static final float QUADRATIC_NAN = Utils.asNan(QUADRATIC);
+ public static final float CONIC_NAN = Utils.asNan(CONIC);
+ public static final float CUBIC_NAN = Utils.asNan(CUBIC);
+ public static final float CLOSE_NAN = Utils.asNan(CLOSE);
+ public static final float DONE_NAN = Utils.asNan(DONE);
+
+ /**
+ *
+ */
+ public static final float ADD = asNan(0x1100);
+ public static final float SUB = asNan(0x1101);
+ public static final float MUL = asNan(0x1102);
+ public static final float DIV = asNan(0x1103);
+ public static final float MOD = asNan(0x1104);
+ public static final float MIN = asNan(0x1105);
+ public static final float MAX = asNan(0x1106);
+ public static final float POW = asNan(0x1107);
+
+
+ /**
+ * Get ID from Nan float
+ * @param v
+ * @return
+ */
+ public static int fromNaN(float v) {
+ int b = Float.floatToRawIntBits(v);
+ return b & 0xFFFFF;
+ }
+
+ /**
+ * Given id return as a Nan float
+ * @param v
+ * @return
+ */
+ public static float asNan(int v) {
+ return Float.intBitsToFloat(v | 0xFF800000);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java
new file mode 100644
index 0000000..8dd5405
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities;
+
+import java.util.Arrays;
+
+/**
+ * Utilities for string manipulation
+ */
+public class StringUtils {
+ /**
+ * Converts a float into a string.
+ * Providing a defined number of characters before and after the
+ * decimal point.
+ *
+ * @param value The value to convert to string
+ * @param beforeDecimalPoint digits before the decimal point
+ * @param afterDecimalPoint digits after the decimal point
+ * @param pre character to pad width 0 = no pad typically ' ' or '0'
+ * @param post character to pad width 0 = no pad typically ' ' or '0'
+ * @return
+ */
+ public static String floatToString(float value,
+ int beforeDecimalPoint,
+ int afterDecimalPoint,
+ char pre, char post) {
+
+ int integerPart = (int) value;
+ float fractionalPart = value % 1;
+
+ // Convert integer part to string and pad with spaces
+ String integerPartString = String.valueOf(integerPart);
+ int iLen = integerPartString.length();
+ if (iLen < beforeDecimalPoint) {
+ int spacesToPad = beforeDecimalPoint - iLen;
+ if (pre != 0) {
+ char[] pad = new char[spacesToPad];
+ Arrays.fill(pad, pre);
+ integerPartString = new String(pad) + integerPartString;
+ }
+
+
+ } else if (iLen > beforeDecimalPoint) {
+ integerPartString = integerPartString.substring(iLen - beforeDecimalPoint);
+ }
+ if (afterDecimalPoint == 0) {
+ return integerPartString;
+ }
+ // Convert fractional part to string and pad with zeros
+
+ for (int i = 0; i < afterDecimalPoint; i++) {
+ fractionalPart *= 10;
+ }
+
+ fractionalPart = Math.round(fractionalPart);
+
+ for (int i = 0; i < afterDecimalPoint; i++) {
+ fractionalPart *= .1;
+ }
+
+ String fact = Float.toString(fractionalPart);
+ fact = fact.substring(2, Math.min(fact.length(), afterDecimalPoint + 2));
+ int trim = fact.length();
+ for (int i = fact.length() - 1; i >= 0; i--) {
+ if (fact.charAt(i) != '0') {
+ break;
+ }
+ trim--;
+ }
+ if (trim != fact.length()) {
+ fact = fact.substring(0, trim);
+ }
+ int len = fact.length();
+ if (post != 0 && len < afterDecimalPoint) {
+ char[] c = new char[afterDecimalPoint - len];
+ Arrays.fill(c, post);
+ fact = fact + new String(c);
+ }
+
+ return integerPartString + "." + fact;
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/BounceCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/BounceCurve.java
new file mode 100644
index 0000000..c3cd5ae9
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/BounceCurve.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+/**
+ * Provide a specific bouncing easing function
+ */
+public class BounceCurve extends Easing {
+ private static final float N1 = 7.5625f;
+ private static final float D1 = 2.75f;
+
+ BounceCurve(int type) {
+ mType = type;
+ }
+
+ @Override
+ public float get(float x) {
+ float t = x;
+ if (t < 0) {
+ return 0f;
+ }
+ if (t < 1 / D1) {
+ return 1 / (1 + 1 / D1) * (N1 * t * t + t);
+ } else if (t < 2 / D1) {
+ t -= 1.5f / D1;
+ return N1 * t * t + 0.75f;
+ } else if (t < 2.5 / D1) {
+ t -= 2.25f / D1;
+ return N1 * t * t + 0.9375f;
+ } else if (t <= 1) {
+ t -= 2.625f / D1;
+ return N1 * t * t + 0.984375f;
+ }
+ return 1f;
+ }
+
+ @Override
+ public float getDiff(float x) {
+ if (x < 0) {
+ return 0f;
+ }
+ if (x < 1 / D1) {
+ return 2 * N1 * x / (1 + 1 / D1) + 1 / (1 + 1 / D1);
+ } else if (x < 2 / D1) {
+ return 2 * N1 * (x - 1.5f / D1);
+ } else if (x < 2.5 / D1) {
+ return 2 * N1 * (x - 2.25f / D1);
+ } else if (x <= 1) {
+ return 2 * N1 * (x - 2.625f / D1);
+ }
+ return 0f;
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java
new file mode 100644
index 0000000..fd1ee03
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+class CubicEasing extends Easing {
+ float mType = 0;
+ float mX1 = 0f;
+ float mY1 = 0f;
+ float mX2 = 0f;
+ float mY2 = 0f;
+
+ private static final float[] STANDARD = {0.4f, 0.0f, 0.2f, 1f};
+ private static final float[] ACCELERATE = {0.4f, 0.05f, 0.8f, 0.7f};
+ private static final float[] DECELERATE = {0.0f, 0.0f, 0.2f, 0.95f};
+ private static final float[] LINEAR = {1f, 1f, 0f, 0f};
+ private static final float[] ANTICIPATE = {0.36f, 0f, 0.66f, -0.56f};
+ private static final float[] OVERSHOOT = {0.34f, 1.56f, 0.64f, 1f};
+
+ CubicEasing(int type) {
+ mType = type;
+ config(type);
+ }
+
+ CubicEasing(float x1, float y1, float x2, float y2) {
+ setup(x1, y1, x2, y2);
+ }
+
+ public void config(int type) {
+
+ switch (type) {
+ case CUBIC_STANDARD:
+ setup(STANDARD);
+ break;
+ case CUBIC_ACCELERATE:
+ setup(ACCELERATE);
+ break;
+ case CUBIC_DECELERATE:
+ setup(DECELERATE);
+ break;
+ case CUBIC_LINEAR:
+ setup(LINEAR);
+ break;
+ case CUBIC_ANTICIPATE:
+ setup(ANTICIPATE);
+ break;
+ case CUBIC_OVERSHOOT:
+ setup(OVERSHOOT);
+ break;
+ }
+ mType = type;
+ }
+
+ void setup(float[] values) {
+ setup(values[0], values[1], values[2], values[3]);
+ }
+
+ void setup(float x1, float y1, float x2, float y2) {
+ mX1 = x1;
+ mY1 = y1;
+ mX2 = x2;
+ mY2 = y2;
+ }
+
+ private float getX(float t) {
+ float t1 = 1 - t;
+ // no need for because start at 0,0 float f0 = (1 - t) * (1 - t) * (1 - t)
+ float f1 = 3 * t1 * t1 * t;
+ float f2 = 3 * t1 * t * t;
+ float f3 = t * t * t;
+ return mX1 * f1 + mX2 * f2 + f3;
+ }
+
+ private float getY(float t) {
+ float t1 = 1 - t;
+ // no need for testing because start at 0,0 float f0 = (1 - t) * (1 - t) * (1 - t)
+ float f1 = 3 * t1 * t1 * t;
+ float f2 = 3 * t1 * t * t;
+ float f3 = t * t * t;
+ return mY1 * f1 + mY2 * f2 + f3;
+ }
+
+ private float getDiffX(float t) {
+ float t1 = 1 - t;
+ return 3 * t1 * t1 * mX1 + 6 * t1 * t * (mX2 - mX1) + 3 * t * t * (1 - mX2);
+ }
+
+ private float getDiffY(float t) {
+ float t1 = 1 - t;
+ return 3 * t1 * t1 * mY1 + 6 * t1 * t * (mY2 - mY1) + 3 * t * t * (1 - mY2);
+ }
+
+ /**
+ * binary search for the region and linear interpolate the answer
+ */
+ public float getDiff(float x) {
+ float t = 0.5f;
+ float range = 0.5f;
+ while (range > D_ERROR) {
+ float tx = getX(t);
+ range *= 0.5;
+ if (tx < x) {
+ t += range;
+ } else {
+ t -= range;
+ }
+ }
+ float x1 = getX(t - range);
+ float x2 = getX(t + range);
+ float y1 = getY(t - range);
+ float y2 = getY(t + range);
+ return (y2 - y1) / (x2 - x1);
+ }
+
+ /**
+ * binary search for the region and linear interpolate the answer
+ */
+ public float get(float x) {
+ if (x <= 0.0f) {
+ return 0f;
+ }
+ if (x >= 1.0f) {
+ return 1.0f;
+ }
+ float t = 0.5f;
+ float range = 0.5f;
+ while (range > ERROR) {
+ float tx = getX(t);
+ range *= 0.5f;
+ if (tx < x) {
+ t += range;
+ } else {
+ t -= range;
+ }
+ }
+ float x1 = getX(t - range);
+ float x2 = getX(t + range);
+ float y1 = getY(t - range);
+ float y2 = getY(t + range);
+ return (y2 - y1) * (x - x1) / (x2 - x1) + y1;
+ }
+
+ private static final float ERROR = 0.01f;
+ private static final float D_ERROR = 0.0001f;
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/Easing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/Easing.java
new file mode 100644
index 0000000..4ed9550
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/Easing.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+/**
+ * The standard interface to Easing functions
+ */
+public abstract class Easing {
+ int mType;
+ /**
+ * get the value at point x
+ */
+ public abstract float get(float x);
+
+ /**
+ * get the slope of the easing function at at x
+ */
+ public abstract float getDiff(float x);
+
+ public int getType() {
+ return mType;
+ }
+
+ public static final int CUBIC_STANDARD = 1;
+ public static final int CUBIC_ACCELERATE = 2;
+ public static final int CUBIC_DECELERATE = 3;
+ public static final int CUBIC_LINEAR = 4;
+ public static final int CUBIC_ANTICIPATE = 5;
+ public static final int CUBIC_OVERSHOOT = 6;
+ public static final int CUBIC_CUSTOM = 11;
+ public static final int SPLINE_CUSTOM = 12;
+ public static final int EASE_OUT_BOUNCE = 13;
+ public static final int EASE_OUT_ELASTIC = 14;
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/ElasticOutCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/ElasticOutCurve.java
new file mode 100644
index 0000000..e269583
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/ElasticOutCurve.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+/**
+ * Provide a bouncing Easing function
+ */
+public class ElasticOutCurve extends Easing {
+ private static final float F_PI = (float) Math.PI;
+ private static final float C4 = 2 * F_PI / 3;
+ private static final float TWENTY_PI = 20 * F_PI;
+ private static final float LOG_8 = (float) Math.log(8.0f);
+
+ @Override
+ public float get(float x) {
+ if (x <= 0) {
+ return 0.0f;
+ }
+ if (x >= 1) {
+ return 1.0f;
+ } else
+ return (float) (Math.pow(2.0f, -10 * x)
+ * Math.sin((x * 10 - 0.75f) * C4) + 1);
+ }
+
+ @Override
+ public float getDiff(float x) {
+ if (x < 0 || x > 1) {
+ return 0.0f;
+ } else
+ return (float) ((5 * Math.pow(2.0f, (1 - 10 * x))
+ * (LOG_8 * Math.cos(TWENTY_PI * x / 3) + 2
+ * F_PI * Math.sin(TWENTY_PI * x / 3))
+ / 3));
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
new file mode 100644
index 0000000..4f484de
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+/**
+ * Support Animation of the FloatExpression
+ */
+public class FloatAnimation extends Easing {
+ float[] mSpec;
+ // mSpec[0] = duration
+ // int(mSpec[1]) = num_of_param << 16 | type
+ // mSpec[2..1+num_of_param] params
+ // mSpec[2+num_of_param] starting Value
+ Easing mEasingCurve;
+ private int mType = CUBIC_STANDARD;
+ private float mDuration = 1;
+ private float mWrap = Float.NaN;
+ private float mInitialValue = Float.NaN;
+ private float mTargetValue = Float.NaN;
+ private float mScale = 1;
+ float mOffset = 0;
+
+ @Override
+ public String toString() {
+
+ String str = "type " + mType;
+ if (!Float.isNaN(mInitialValue)) {
+ str += " " + mInitialValue;
+ }
+ if (!Float.isNaN(mTargetValue)) {
+ str += " -> " + mTargetValue;
+ }
+ if (!Float.isNaN(mWrap)) {
+ str += " % " + mWrap;
+ }
+
+ return str;
+ }
+
+ public FloatAnimation() {
+ }
+
+ public FloatAnimation(float... description) {
+ setAnimationDescription(description);
+ }
+
+ public FloatAnimation(int type,
+ float duration,
+ float[] description,
+ float initialValue,
+ float wrap) {
+ setAnimationDescription(packToFloatArray(duration,
+ type, description, initialValue, wrap));
+ }
+
+ /**
+ * packs spec into a float array
+ *
+ * @param duration
+ * @param type
+ * @param spec
+ * @param initialValue
+ * @return
+ */
+ public static float[] packToFloatArray(float duration,
+ int type,
+ float[] spec,
+ float initialValue,
+ float wrap) {
+ int count = 0;
+
+ if (!Float.isNaN(initialValue)) {
+ count++;
+ }
+ if (spec != null) {
+ count++;
+ }
+ if (spec != null || type != CUBIC_STANDARD) {
+ count++;
+ count += (spec == null) ? 0 : spec.length;
+ }
+ if (duration != 1 || count > 0) {
+ count++;
+ }
+ if (!Float.isNaN(initialValue)) {
+ count++;
+ }
+ if (!Float.isNaN(wrap)) {
+ count++;
+ }
+ float[] ret = new float[count];
+ int pos = 0;
+ int specLen = (spec == null) ? 0 : spec.length;
+
+ if (ret.length > 0) {
+ ret[pos++] = duration;
+
+ }
+ if (ret.length > 1) {
+ int wrapBit = (Float.isNaN(wrap)) ? 0 : 1;
+ int initBit = (Float.isNaN(initialValue)) ? 0 : 2;
+ int bits = type | ((wrapBit | initBit) << 8);
+ ret[pos++] = Float.intBitsToFloat(specLen << 16 | bits);
+ }
+
+ if (specLen > 0) {
+ System.arraycopy(spec, 0, ret, pos, spec.length);
+ pos += spec.length;
+ }
+ if (!Float.isNaN(initialValue)) {
+ ret[pos++] = initialValue;
+ }
+ if (!Float.isNaN(wrap)) {
+ ret[pos] = wrap;
+ }
+ return ret;
+ }
+
+ /**
+ * Create an animation based on a float encoding of the animation
+ * @param description
+ */
+ public void setAnimationDescription(float[] description) {
+ mSpec = description;
+ mDuration = (mSpec.length == 0) ? 1 : mSpec[0];
+ int len = 0;
+ if (mSpec.length > 1) {
+ int num_type = Float.floatToRawIntBits(mSpec[1]);
+ mType = num_type & 0xFF;
+ boolean wrap = ((num_type >> 8) & 0x1) > 0;
+ boolean init = ((num_type >> 8) & 0x2) > 0;
+ len = (num_type >> 16) & 0xFFFF;
+ int off = 2 + len;
+ if (init) {
+ mInitialValue = mSpec[off++];
+ }
+ if (wrap) {
+ mWrap = mSpec[off];
+ }
+ }
+ create(mType, description, 2, len);
+ }
+
+ private void create(int type, float[] params, int offset, int len) {
+ switch (type) {
+ case CUBIC_STANDARD:
+ case CUBIC_ACCELERATE:
+ case CUBIC_DECELERATE:
+ case CUBIC_LINEAR:
+ case CUBIC_ANTICIPATE:
+ case CUBIC_OVERSHOOT:
+ mEasingCurve = new CubicEasing(type);
+ break;
+ case CUBIC_CUSTOM:
+ mEasingCurve = new CubicEasing(params[offset + 0],
+ params[offset + 1],
+ params[offset + 2],
+ params[offset + 3]
+ );
+ break;
+ case EASE_OUT_BOUNCE:
+ mEasingCurve = new BounceCurve(type);
+ break;
+ case EASE_OUT_ELASTIC:
+ mEasingCurve = new ElasticOutCurve();
+ break;
+ case SPLINE_CUSTOM:
+ mEasingCurve = new StepCurve(params, offset, len);
+ break;
+ }
+ }
+
+ /**
+ * Get the duration the interpolate is to take
+ * @return duration in seconds
+ */
+ public float getDuration() {
+ return mDuration;
+ }
+
+ /**
+ * Set the initial Value
+ * @param value
+ */
+ public void setInitialValue(float value) {
+
+ if (Float.isNaN(mWrap)) {
+ mInitialValue = value;
+ } else {
+ mInitialValue = value % mWrap;
+ }
+ setScaleOffset();
+ }
+
+ /**
+ * Set the target value to interpolate to
+ * @param value
+ */
+ public void setTargetValue(float value) {
+ if (Float.isNaN(mWrap)) {
+ mTargetValue = value;
+ } else {
+ if (Math.abs((value % mWrap) + mWrap - mInitialValue)
+ < Math.abs((value % mWrap) - mInitialValue)) {
+ mTargetValue = (value % mWrap) + mWrap;
+
+ } else {
+ mTargetValue = value % mWrap;
+ }
+ }
+ setScaleOffset();
+ }
+
+ public float getTargetValue() {
+ return mTargetValue;
+ }
+
+ private void setScaleOffset() {
+ if (!Float.isNaN(mInitialValue) && !Float.isNaN(mTargetValue)) {
+ mScale = (mTargetValue - mInitialValue);
+ mOffset = mInitialValue;
+ } else {
+ mScale = 1;
+ mOffset = 0;
+ }
+ }
+
+ /**
+ * get the value at time t in seconds since start
+ */
+ public float get(float t) {
+ return mEasingCurve.get(t / mDuration)
+ * (mTargetValue - mInitialValue) + mInitialValue;
+ }
+
+ /**
+ * get the slope of the easing function at at x
+ */
+ public float getDiff(float t) {
+ return mEasingCurve.getDiff(t / mDuration) * (mTargetValue - mInitialValue);
+ }
+
+ public float getInitialValue() {
+ return mInitialValue;
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java
new file mode 100644
index 0000000..693deaf
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+/**
+ * Provides and interface to create easing functions
+ */
+public class GeneralEasing extends Easing{
+ float[] mEasingData = new float[0];
+ Easing mEasingCurve = new CubicEasing(CUBIC_STANDARD);
+
+ /**
+ * Set the curve based on the float encoding of it
+ * @param data
+ */
+ public void setCurveSpecification(float[] data) {
+ mEasingData = data;
+ createEngine();
+ }
+
+ public float[] getCurveSpecification() {
+ return mEasingData;
+ }
+
+ void createEngine() {
+ int type = Float.floatToRawIntBits(mEasingData[0]);
+ switch (type) {
+ case CUBIC_STANDARD:
+ case CUBIC_ACCELERATE:
+ case CUBIC_DECELERATE:
+ case CUBIC_LINEAR:
+ case CUBIC_ANTICIPATE:
+ case CUBIC_OVERSHOOT:
+ mEasingCurve = new CubicEasing(type);
+ break;
+ case CUBIC_CUSTOM:
+ mEasingCurve = new CubicEasing(mEasingData[1],
+ mEasingData[2],
+ mEasingData[3],
+ mEasingData[5]
+ );
+ break;
+ case EASE_OUT_BOUNCE:
+ mEasingCurve = new BounceCurve(type);
+ break;
+ }
+ }
+
+ /**
+ * get the value at point x
+ */
+ public float get(float x) {
+ return mEasingCurve.get(x);
+ }
+
+ /**
+ * get the slope of the easing function at at x
+ */
+ public float getDiff(float x) {
+ return mEasingCurve.getDiff(x);
+ }
+
+ public int getType() {
+ return mEasingCurve.getType();
+ }
+
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java
new file mode 100644
index 0000000..23930b9
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+import java.util.Arrays;
+
+/**
+ * This performs a spline interpolation in multiple dimensions
+ *
+ *
+ */
+public class MonotonicCurveFit {
+ private static final String TAG = "MonotonicCurveFit";
+ private double[] mT;
+ private double[][] mY;
+ private double[][] mTangent;
+ private boolean mExtrapolate = true;
+ double[] mSlopeTemp;
+
+ /**
+ * create a collection of curves
+ * @param time the point along the curve
+ * @param y the parameter at those points
+ */
+ public MonotonicCurveFit(double[] time, double[][] y) {
+ final int n = time.length;
+ final int dim = y[0].length;
+ mSlopeTemp = new double[dim];
+ double[][] slope = new double[n - 1][dim]; // could optimize this out
+ double[][] tangent = new double[n][dim];
+ for (int j = 0; j < dim; j++) {
+ for (int i = 0; i < n - 1; i++) {
+ double dt = time[i + 1] - time[i];
+ slope[i][j] = (y[i + 1][j] - y[i][j]) / dt;
+ if (i == 0) {
+ tangent[i][j] = slope[i][j];
+ } else {
+ tangent[i][j] = (slope[i - 1][j] + slope[i][j]) * 0.5f;
+ }
+ }
+ tangent[n - 1][j] = slope[n - 2][j];
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ for (int j = 0; j < dim; j++) {
+ if (slope[i][j] == 0.) {
+ tangent[i][j] = 0.;
+ tangent[i + 1][j] = 0.;
+ } else {
+ double a = tangent[i][j] / slope[i][j];
+ double b = tangent[i + 1][j] / slope[i][j];
+ double h = Math.hypot(a, b);
+ if (h > 9.0) {
+ double t = 3. / h;
+ tangent[i][j] = t * a * slope[i][j];
+ tangent[i + 1][j] = t * b * slope[i][j];
+ }
+ }
+ }
+ }
+ mT = time;
+ mY = y;
+ mTangent = tangent;
+ }
+
+ /**
+ * Get the position of all curves at time t
+ * @param t
+ * @param v
+ */
+ public void getPos(double t, double[] v) {
+ final int n = mT.length;
+ final int dim = mY[0].length;
+ if (mExtrapolate) {
+ if (t <= mT[0]) {
+ getSlope(mT[0], mSlopeTemp);
+ for (int j = 0; j < dim; j++) {
+ v[j] = mY[0][j] + (t - mT[0]) * mSlopeTemp[j];
+ }
+ return;
+ }
+ if (t >= mT[n - 1]) {
+ getSlope(mT[n - 1], mSlopeTemp);
+ for (int j = 0; j < dim; j++) {
+ v[j] = mY[n - 1][j] + (t - mT[n - 1]) * mSlopeTemp[j];
+ }
+ return;
+ }
+ } else {
+ if (t <= mT[0]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = mY[0][j];
+ }
+ return;
+ }
+ if (t >= mT[n - 1]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = mY[n - 1][j];
+ }
+ return;
+ }
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ if (t == mT[i]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = mY[i][j];
+ }
+ }
+ if (t < mT[i + 1]) {
+ double h = mT[i + 1] - mT[i];
+ double x = (t - mT[i]) / h;
+ for (int j = 0; j < dim; j++) {
+ double y1 = mY[i][j];
+ double y2 = mY[i + 1][j];
+ double t1 = mTangent[i][j];
+ double t2 = mTangent[i + 1][j];
+ v[j] = interpolate(h, x, y1, y2, t1, t2);
+ }
+ return;
+ }
+ }
+ }
+
+ /**
+ * Get the position of all curves at time t
+ * @param t
+ * @param v
+ */
+ public void getPos(double t, float[] v) {
+ final int n = mT.length;
+ final int dim = mY[0].length;
+ if (mExtrapolate) {
+ if (t <= mT[0]) {
+ getSlope(mT[0], mSlopeTemp);
+ for (int j = 0; j < dim; j++) {
+ v[j] = (float) (mY[0][j] + (t - mT[0]) * mSlopeTemp[j]);
+ }
+ return;
+ }
+ if (t >= mT[n - 1]) {
+ getSlope(mT[n - 1], mSlopeTemp);
+ for (int j = 0; j < dim; j++) {
+ v[j] = (float) (mY[n - 1][j] + (t - mT[n - 1]) * mSlopeTemp[j]);
+ }
+ return;
+ }
+ } else {
+ if (t <= mT[0]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = (float) mY[0][j];
+ }
+ return;
+ }
+ if (t >= mT[n - 1]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = (float) mY[n - 1][j];
+ }
+ return;
+ }
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ if (t == mT[i]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = (float) mY[i][j];
+ }
+ }
+ if (t < mT[i + 1]) {
+ double h = mT[i + 1] - mT[i];
+ double x = (t - mT[i]) / h;
+ for (int j = 0; j < dim; j++) {
+ double y1 = mY[i][j];
+ double y2 = mY[i + 1][j];
+ double t1 = mTangent[i][j];
+ double t2 = mTangent[i + 1][j];
+ v[j] = (float) interpolate(h, x, y1, y2, t1, t2);
+ }
+ return;
+ }
+ }
+ }
+
+ /**
+ * Get the position of the jth curve at time t
+ * @param t
+ * @param j
+ * @return
+ */
+ public double getPos(double t, int j) {
+ final int n = mT.length;
+ if (mExtrapolate) {
+ if (t <= mT[0]) {
+ return mY[0][j] + (t - mT[0]) * getSlope(mT[0], j);
+ }
+ if (t >= mT[n - 1]) {
+ return mY[n - 1][j] + (t - mT[n - 1]) * getSlope(mT[n - 1], j);
+ }
+ } else {
+ if (t <= mT[0]) {
+ return mY[0][j];
+ }
+ if (t >= mT[n - 1]) {
+ return mY[n - 1][j];
+ }
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ if (t == mT[i]) {
+ return mY[i][j];
+ }
+ if (t < mT[i + 1]) {
+ double h = mT[i + 1] - mT[i];
+ double x = (t - mT[i]) / h;
+ double y1 = mY[i][j];
+ double y2 = mY[i + 1][j];
+ double t1 = mTangent[i][j];
+ double t2 = mTangent[i + 1][j];
+ return interpolate(h, x, y1, y2, t1, t2);
+
+ }
+ }
+ return 0; // should never reach here
+ }
+
+ /**
+ * Get the slope of all the curves at position t
+ * @param t
+ * @param v
+ */
+ public void getSlope(double t, double[] v) {
+ final int n = mT.length;
+ int dim = mY[0].length;
+ if (t <= mT[0]) {
+ t = mT[0];
+ } else if (t >= mT[n - 1]) {
+ t = mT[n - 1];
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ if (t <= mT[i + 1]) {
+ double h = mT[i + 1] - mT[i];
+ double x = (t - mT[i]) / h;
+ for (int j = 0; j < dim; j++) {
+ double y1 = mY[i][j];
+ double y2 = mY[i + 1][j];
+ double t1 = mTangent[i][j];
+ double t2 = mTangent[i + 1][j];
+ v[j] = diff(h, x, y1, y2, t1, t2) / h;
+ }
+ break;
+ }
+ }
+ return;
+ }
+
+ /**
+ * Get the slope of the j curve at position t
+ * @param t
+ * @param j
+ * @return
+ */
+ public double getSlope(double t, int j) {
+ final int n = mT.length;
+
+ if (t < mT[0]) {
+ t = mT[0];
+ } else if (t >= mT[n - 1]) {
+ t = mT[n - 1];
+ }
+ for (int i = 0; i < n - 1; i++) {
+ if (t <= mT[i + 1]) {
+ double h = mT[i + 1] - mT[i];
+ double x = (t - mT[i]) / h;
+ double y1 = mY[i][j];
+ double y2 = mY[i + 1][j];
+ double t1 = mTangent[i][j];
+ double t2 = mTangent[i + 1][j];
+ return diff(h, x, y1, y2, t1, t2) / h;
+ }
+ }
+ return 0; // should never reach here
+ }
+
+ public double[] getTimePoints() {
+ return mT;
+ }
+
+ /**
+ * Cubic Hermite spline
+ */
+ private static double interpolate(double h,
+ double x,
+ double y1,
+ double y2,
+ double t1,
+ double t2) {
+ double x2 = x * x;
+ double x3 = x2 * x;
+ return -2 * x3 * y2 + 3 * x2 * y2 + 2 * x3 * y1 - 3 * x2 * y1 + y1
+ + h * t2 * x3 + h * t1 * x3 - h * t2 * x2 - 2 * h * t1 * x2
+ + h * t1 * x;
+ }
+
+ /**
+ * Cubic Hermite spline slope differentiated
+ */
+ private static double diff(double h, double x, double y1, double y2, double t1, double t2) {
+ double x2 = x * x;
+ return -6 * x2 * y2 + 6 * x * y2 + 6 * x2 * y1 - 6 * x * y1 + 3 * h * t2 * x2
+ + 3 * h * t1 * x2 - 2 * h * t2 * x - 4 * h * t1 * x + h * t1;
+ }
+
+ /**
+ * This builds a monotonic spline to be used as a wave function
+ */
+ public static MonotonicCurveFit buildWave(String configString) {
+ // done this way for efficiency
+ String str = configString;
+ double[] values = new double[str.length() / 2];
+ int start = configString.indexOf('(') + 1;
+ int off1 = configString.indexOf(',', start);
+ int count = 0;
+ while (off1 != -1) {
+ String tmp = configString.substring(start, off1).trim();
+ values[count++] = Double.parseDouble(tmp);
+ off1 = configString.indexOf(',', start = off1 + 1);
+ }
+ off1 = configString.indexOf(')', start);
+ String tmp = configString.substring(start, off1).trim();
+ values[count++] = Double.parseDouble(tmp);
+
+ return buildWave(Arrays.copyOf(values, count));
+ }
+
+ private static MonotonicCurveFit buildWave(double[] values) {
+ int length = values.length * 3 - 2;
+ int len = values.length - 1;
+ double gap = 1.0 / len;
+ double[][] points = new double[length][1];
+ double[] time = new double[length];
+ for (int i = 0; i < values.length; i++) {
+ double v = values[i];
+ points[i + len][0] = v;
+ time[i + len] = i * gap;
+ if (i > 0) {
+ points[i + len * 2][0] = v + 1;
+ time[i + len * 2] = i * gap + 1;
+
+ points[i - 1][0] = v - 1 - gap;
+ time[i - 1] = i * gap + -1 - gap;
+ }
+ }
+
+ return new MonotonicCurveFit(time, points);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java
new file mode 100644
index 0000000..6ed6548
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+
+/**
+ * This class translates a series of floating point values into a continuous
+ * curve for use in an easing function including quantize functions
+ * it is used with the "spline(0,0.3,0.3,0.5,...0.9,1)" it should start at 0 and end at one 1
+ */
+public class StepCurve extends Easing {
+ private static final boolean DEBUG = false;
+ MonotonicCurveFit mCurveFit;
+
+ public StepCurve(float[] params, int offset, int len) {
+ mCurveFit = genSpline(params, offset, len);
+ }
+
+ private static MonotonicCurveFit genSpline(float[] values, int off, int arrayLen) {
+ int length = arrayLen * 3 - 2;
+ int len = arrayLen - 1;
+ double gap = 1.0 / len;
+ double[][] points = new double[length][1];
+ double[] time = new double[length];
+ for (int i = 0; i < arrayLen; i++) {
+ double v = values[i + off];
+ points[i + len][0] = v;
+ time[i + len] = i * gap;
+ if (i > 0) {
+ points[i + len * 2][0] = v + 1;
+ time[i + len * 2] = i * gap + 1;
+
+ points[i - 1][0] = v - 1 - gap;
+ time[i - 1] = i * gap + -1 - gap;
+ }
+ }
+
+ MonotonicCurveFit ms = new MonotonicCurveFit(time, points);
+
+ return ms;
+ }
+
+ @Override
+ public float getDiff(float x) {
+ return (float) mCurveFit.getSlope(x, 0);
+ }
+
+
+ @Override
+ public float get(float x) {
+ return (float) mCurveFit.getPos(x, 0);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
index bcda27a..d1c4d46 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
@@ -79,6 +79,15 @@
}
/**
+ * The delay in milliseconds to next repaint -1 = not needed 0 = asap
+ *
+ * @return delay in milliseconds to next repaint or -1
+ */
+ public int needsRepaint() {
+ return mDocument.needsRepaint();
+ }
+
+ /**
* Returns true if the document can be displayed given this version of the player
*
* @param majorVersion the max major version supported by the player
@@ -89,5 +98,10 @@
return mDocument.canBeDisplayed(majorVersion, minorVersion, capabilities);
}
+ @Override
+ public String toString() {
+ return "Document{\n"
+ + mDocument + '}';
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
index d0d6e69..ecb68bb 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
@@ -26,6 +26,7 @@
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.RuntimeShader;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.Typeface;
@@ -33,6 +34,8 @@
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.operations.ClipPath;
+import com.android.internal.widget.remotecompose.core.operations.ShaderData;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintChanges;
@@ -43,6 +46,7 @@
public class AndroidPaintContext extends PaintContext {
Paint mPaint = new Paint();
Canvas mCanvas;
+ Rect mTmpRect = new Rect(); // use in calculation of bounds
public AndroidPaintContext(RemoteContext context, Canvas canvas) {
super(context);
@@ -177,6 +181,22 @@
}
@Override
+ public void getTextBounds(int textId, int start, int end, boolean monospace, float[] bounds) {
+ String str = getText(textId);
+ if (end == -1) {
+ end = str.length();
+ }
+
+ mPaint.getTextBounds(str, start, end, mTmpRect);
+
+ bounds[0] = mTmpRect.left;
+ bounds[1] = mTmpRect.top;
+ bounds[2] = monospace ? (mPaint.measureText(str, start, end) - mTmpRect.left)
+ : mTmpRect.right;
+ bounds[3] = mTmpRect.bottom;
+ }
+
+ @Override
public void drawTextRun(int textID,
int start,
int end,
@@ -185,7 +205,16 @@
float x,
float y,
boolean rtl) {
- String textToPaint = getText(textID).substring(start, end);
+
+ String textToPaint = getText(textID);
+ if (end == -1) {
+ if (start != 0) {
+ textToPaint = textToPaint.substring(start);
+ }
+ } else {
+ textToPaint = textToPaint.substring(start, end);
+ }
+
mCanvas.drawText(textToPaint, x, y, mPaint);
}
@@ -308,7 +337,7 @@
@Override
public void applyPaint(PaintBundle mPaintData) {
- mPaintData.applyPaintChange(new PaintChanges() {
+ mPaintData.applyPaintChange((PaintContext) this, new PaintChanges() {
@Override
public void setTextSize(float size) {
mPaint.setTextSize(size);
@@ -361,10 +390,8 @@
}
}
-
}
-
@Override
public void setStrokeWidth(float width) {
mPaint.setStrokeWidth(width);
@@ -386,13 +413,37 @@
}
@Override
- public void setShader(int shader, String shaderString) {
-
+ public void setShader(int shaderId) {
+ // TODO this stuff should check the shader creation
+ if (shaderId == 0) {
+ mPaint.setShader(null);
+ return;
+ }
+ ShaderData data = getShaderData(shaderId);
+ RuntimeShader shader = new RuntimeShader(getText(data.getShaderTextId()));
+ String[] names = data.getUniformFloatNames();
+ for (int i = 0; i < names.length; i++) {
+ String name = names[i];
+ float[] val = data.getUniformFloats(name);
+ shader.setFloatUniform(name, val);
+ }
+ names = data.getUniformIntegerNames();
+ for (int i = 0; i < names.length; i++) {
+ String name = names[i];
+ int[] val = data.getUniformInts(name);
+ shader.setIntUniform(name, val);
+ }
+ names = data.getUniformBitmapNames();
+ for (int i = 0; i < names.length; i++) {
+ String name = names[i];
+ int val = data.getUniformBitmapId(name);
+ }
+ mPaint.setShader(shader);
}
@Override
public void setImageFilterQuality(int quality) {
- System.out.println(">>>>>>>>>>>> ");
+ Utils.log(" quality =" + quality);
}
@Override
@@ -420,7 +471,6 @@
mPaint.setFilterBitmap(filter);
}
-
@Override
public void setAntiAlias(boolean aa) {
mPaint.setAntiAlias(aa);
@@ -437,7 +487,6 @@
case PaintBundle.COLOR_FILTER:
mPaint.setColorFilter(null);
- System.out.println(">>>>>>>>>>>>> CLEAR!!!!");
break;
}
}
@@ -446,12 +495,11 @@
}
}
- Shader.TileMode[] mTilesModes = new Shader.TileMode[]{
+ Shader.TileMode[] mTileModes = new Shader.TileMode[]{
Shader.TileMode.CLAMP,
Shader.TileMode.REPEAT,
Shader.TileMode.MIRROR};
-
@Override
public void setLinearGradient(int[] colors,
float[] stops,
@@ -463,7 +511,7 @@
mPaint.setShader(new LinearGradient(startX,
startY,
endX,
- endY, colors, stops, mTilesModes[tileMode]));
+ endY, colors, stops, mTileModes[tileMode]));
}
@@ -475,7 +523,7 @@
float radius,
int tileMode) {
mPaint.setShader(new RadialGradient(centerX, centerY, radius,
- colors, stops, mTilesModes[tileMode]));
+ colors, stops, mTileModes[tileMode]));
}
@Override
@@ -490,7 +538,6 @@
@Override
public void setColorFilter(int color, int mode) {
PorterDuff.Mode pmode = origamiToPorterDuffMode(mode);
- System.out.println("setting color filter to " + pmode.name());
if (pmode != null) {
mPaint.setColorFilter(
new PorterDuffColorFilter(color, pmode));
@@ -500,10 +547,10 @@
}
@Override
- public void mtrixScale(float scaleX,
- float scaleY,
- float centerX,
- float centerY) {
+ public void matrixScale(float scaleX,
+ float scaleY,
+ float centerX,
+ float centerY) {
if (Float.isNaN(centerX)) {
mCanvas.scale(scaleX, scaleY);
} else {
@@ -556,6 +603,11 @@
}
}
+ @Override
+ public void reset() {
+ mPaint.reset();
+ }
+
private Path getPath(int path1Id,
int path2Id,
float tween,
@@ -599,5 +651,9 @@
private String getText(int id) {
return (String) mContext.mRemoteComposeState.getFromId(id);
}
+
+ private ShaderData getShaderData(int id) {
+ return (ShaderData) mContext.mRemoteComposeState.getFromId(id);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
index 270e96f..6e4893b 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
@@ -20,10 +20,15 @@
import android.graphics.Canvas;
import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
+import com.android.internal.widget.remotecompose.core.operations.ShaderData;
+
+import java.util.HashMap;
/**
* An implementation of Context for Android.
- *
+ * <p>
* This is used to play the RemoteCompose operations on Android.
*/
class AndroidRemoteContext extends RemoteContext {
@@ -33,6 +38,7 @@
mPaintContext = new AndroidPaintContext(this, canvas);
} else {
// need to make sure to update the canvas for the current one
+ mPaintContext.reset();
((AndroidPaintContext) mPaintContext).setCanvas(canvas);
}
mWidth = canvas.getWidth();
@@ -50,13 +56,32 @@
}
}
+ static class VarName {
+ String mName;
+ int mId;
+ int mType;
+
+ VarName(String name, int id, int type) {
+ mName = name;
+ mId = id;
+ mType = type;
+ }
+ }
+
+ HashMap<String, VarName> mVarNameHashMap = new HashMap<>();
+
+ @Override
+ public void loadVariableName(String varName, int varId, int varType) {
+ mVarNameHashMap.put(varName, new VarName(varName, varId, varType));
+ }
+
/**
* Decode a byte array into an image and cache it using the given imageId
*
- * @oaram imageId the id of the image
- * @param width with of image to be loaded
+ * @param width with of image to be loaded
* @param height height of image to be loaded
* @param bitmap a byte array containing the image information
+ * @oaram imageId the id of the image
*/
@Override
public void loadBitmap(int imageId, int width, int height, byte[] bitmap) {
@@ -70,14 +95,66 @@
public void loadText(int id, String text) {
if (!mRemoteComposeState.containsId(id)) {
mRemoteComposeState.cache(id, text);
+ } else {
+ mRemoteComposeState.update(id, text);
}
}
+ @Override
+ public String getText(int id) {
+ return (String) mRemoteComposeState.getFromId(id);
+ }
+
+ @Override
+ public void loadFloat(int id, float value) {
+ mRemoteComposeState.updateFloat(id, value);
+ }
+
+
+ @Override
+ public void loadColor(int id, int color) {
+ mRemoteComposeState.updateColor(id, color);
+ }
+
+ @Override
+ public void loadAnimatedFloat(int id, FloatExpression animatedFloat) {
+ mRemoteComposeState.cache(id, animatedFloat);
+ }
+
+ @Override
+ public void loadShader(int id, ShaderData value) {
+ mRemoteComposeState.cache(id, value);
+ }
+
+ @Override
+ public float getFloat(int id) {
+ return (float) mRemoteComposeState.getFloat(id);
+ }
+
+ @Override
+ public int getColor(int id) {
+ return mRemoteComposeState.getColor(id);
+ }
+
+ @Override
+ public void listensTo(int id, VariableSupport variableSupport) {
+ mRemoteComposeState.listenToVar(id, variableSupport);
+ }
+
+ @Override
+ public int updateOps() {
+ return mRemoteComposeState.getOpsToUpdate(this);
+ }
+
+ @Override
+ public ShaderData getShader(int id) {
+ return (ShaderData) mRemoteComposeState.getFromId(id);
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////////
// Click handling
///////////////////////////////////////////////////////////////////////////////////////////////
-
@Override
public void addClickArea(int id,
int contentDescriptionId,
@@ -87,7 +164,7 @@
float bottom,
int metadataId) {
String contentDescription = (String) mRemoteComposeState.getFromId(contentDescriptionId);
- String metadata = (String) mRemoteComposeState.getFromId(metadataId);
+ String metadata = (String) mRemoteComposeState.getFromId(metadataId);
mDocument.addClickArea(id, contentDescription, left, top, right, bottom, metadata);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java b/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
index 672dae3..329178a 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
@@ -20,7 +20,6 @@
import android.graphics.Paint;
import android.view.View;
-
/**
* Implementation for the click handling
*/
@@ -40,7 +39,6 @@
setContentDescription(contentDescription);
}
-
public void setDebug(boolean value) {
if (mDebug != value) {
mDebug = value;
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
index a3bb73e..97d23c8 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
@@ -85,6 +85,7 @@
mDocument.initializeContext(mARContext);
setContentDescription(mDocument.getDocument().getContentDescription());
requestLayout();
+ invalidate();
}
AndroidRemoteContext mARContext = new AndroidRemoteContext();
@@ -119,8 +120,7 @@
removeAllViews();
}
-
- public interface ClickCallbacks {
+ public interface ClickCallbacks {
void click(int id, String metadata);
}
@@ -213,6 +213,9 @@
setMeasuredDimension(w, h);
}
+ private int mCount;
+ private long mTime = System.nanoTime();
+
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
@@ -224,6 +227,17 @@
mARContext.mWidth = getWidth();
mARContext.mHeight = getHeight();
mDocument.paint(mARContext, mTheme);
+ if (mDebug) {
+ mCount++;
+ if (System.nanoTime() - mTime > 1000000000L) {
+ System.out.println(" count " + mCount + " fps");
+ mCount = 0;
+ mTime = System.nanoTime();
+ }
+ }
+ if (mDocument.needsRepaint() > 0) {
+ invalidate();
+ }
}
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index e831a7d..5365838 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -358,7 +358,8 @@
jobject stats =
env->NewObject(gTransactionStatsClassInfo.clazz, gTransactionStatsClassInfo.ctor,
- latchTime, presentFence.get());
+ latchTime,
+ static_cast<jlong>(reinterpret_cast<uintptr_t>(presentFence.get())));
env->CallVoidMethod(mTransactionCompletedListenerObject, gConsumerClassInfo.accept, stats);
env->DeleteLocalRef(stats);
DieIfException(env, "Uncaught exception in TransactionCompletedListener.");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c6db371..c71f9bd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3326,13 +3326,18 @@
<!-- Allows an application to manage device policy relating to time.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
- APIs protected by this permission on users different to the calling user.-->
+ APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_TIME"
android:protectionLevel="internal|role" />
<!-- Allows an application to set the grant state of runtime permissions on packages.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS"
android:protectionLevel="internal|role" />
@@ -3340,6 +3345,8 @@
<!-- Allows an application to manage the identity of the managing organization.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY"
android:protectionLevel="internal|role" />
@@ -3348,6 +3355,8 @@
active policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE"
android:protectionLevel="internal|role" />
@@ -3355,6 +3364,8 @@
<!-- Allows an application to manage backup service policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_BACKUP_SERVICE"
android:protectionLevel="internal|role" />
@@ -3362,6 +3373,8 @@
<!-- Allows an application to manage lock task policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_TASK"
android:protectionLevel="internal|role" />
@@ -3369,6 +3382,8 @@
<!-- Allows an application to manage policy regarding modifying applications.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL"
android:protectionLevel="internal|role" />
@@ -3376,6 +3391,8 @@
<!-- Allows an application to manage installing from unknown sources policy.
<p>MANAGE_SECURITY_CRITICAL_DEVICE_POLICY_ACROSS_USERS is required to call APIs protected
by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES"
android:protectionLevel="internal|role" />
@@ -3383,6 +3400,8 @@
<!-- Allows an application to manage application restrictions.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS"
android:protectionLevel="internal|role" />
@@ -3390,6 +3409,8 @@
<!-- Allows an application to manage calling policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_CALLS"
android:protectionLevel="internal|role" />
@@ -3397,6 +3418,8 @@
<!-- Allows an application to manage debugging features policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES"
android:protectionLevel="internal|role" />
@@ -3404,6 +3427,8 @@
<!-- Allows an application to manage policy preventing users from modifying users.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS"
android:protectionLevel="internal|role" />
@@ -3411,6 +3436,8 @@
<!-- Allows an application to manage safe boot policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SAFE_BOOT"
android:protectionLevel="internal|role" />
@@ -3419,6 +3446,8 @@
enable and disable the microphone.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MICROPHONE"
android:protectionLevel="internal|role" />
@@ -3427,6 +3456,8 @@
enable and disable the camera.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_CAMERA"
android:protectionLevel="internal|role" />
@@ -3434,6 +3465,8 @@
<!-- Allows an application to manage policy related to keyguard.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEYGUARD"
android:protectionLevel="internal|role" />
@@ -3441,6 +3474,8 @@
<!-- Allows an application to set policy related to account management.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT"
android:protectionLevel="internal|role" />
@@ -3448,6 +3483,8 @@
<!-- Allows an application to set policy related to hiding and suspending packages.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE"
android:protectionLevel="internal|role" />
@@ -3456,17 +3493,24 @@
challenge on current user.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD"
android:protectionLevel="internal|role" />
- <!-- Allows an application to set policy related to the status bar.-->
+ <!-- Allows an application to set policy related to the status bar.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_STATUS_BAR"
android:protectionLevel="internal|role" />
<!-- Allows an application to set policy related to bluetooth.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_BLUETOOTH"
android:protectionLevel="internal|role" />
@@ -3474,6 +3518,8 @@
<!-- Allows an application to set policy related to fun.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_FUN"
android:protectionLevel="internal|role" />
@@ -3481,6 +3527,8 @@
<!-- Allows an application to set policy related to airplane mode.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_AIRPLANE_MODE"
android:protectionLevel="internal|role" />
@@ -3488,6 +3536,8 @@
<!-- Allows an application to set policy related to mobile networks.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK"
android:protectionLevel="internal|role" />
@@ -3495,6 +3545,8 @@
<!-- Allows an application to set policy related to physical media.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA"
android:protectionLevel="internal|role" />
@@ -3502,6 +3554,8 @@
<!-- Allows an application to set policy related to sms.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SMS"
android:protectionLevel="internal|role" />
@@ -3509,6 +3563,8 @@
<!-- Allows an application to set policy related to usb file transfers.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER"
android:protectionLevel="internal|role" />
@@ -3516,6 +3572,8 @@
<!-- Allows an application to set policy related to lock credentials.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS"
android:protectionLevel="internal|role" />
@@ -3523,6 +3581,8 @@
<!-- Allows an application to set policy related to Wifi.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIFI"
android:protectionLevel="internal|role" />
@@ -3530,6 +3590,8 @@
<!-- Allows an application to set policy related to screen capture.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SCREEN_CAPTURE"
android:protectionLevel="internal|role" />
@@ -3537,6 +3599,8 @@
<!-- Allows an application to set policy related to input methods.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_INPUT_METHODS"
android:protectionLevel="internal|role" />
@@ -3545,6 +3609,8 @@
private DNS.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS"
android:protectionLevel="internal|role" />
@@ -3552,6 +3618,8 @@
<!-- Allows an application to set policy related to the default sms application.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS"
android:protectionLevel="internal|role" />
@@ -3559,6 +3627,8 @@
<!-- Allows an application to set policy related to profiles.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROFILES"
android:protectionLevel="internal|role" />
@@ -3567,6 +3637,8 @@
cross-profile copy and paste).
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION"
android:protectionLevel="internal|role" />
@@ -3574,6 +3646,8 @@
<!-- Allows an application to set policy related to VPNs.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_VPN"
android:protectionLevel="internal|role" />
@@ -3581,6 +3655,8 @@
<!-- Allows an application to set policy related to audio output.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT"
android:protectionLevel="internal|role" />
@@ -3588,6 +3664,8 @@
<!-- Allows an application to set policy related to the display.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_DISPLAY"
android:protectionLevel="internal|role" />
@@ -3595,6 +3673,8 @@
<!-- Allows an application to set policy related to location.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCATION"
android:protectionLevel="internal|role" />
@@ -3602,6 +3682,8 @@
<!-- Allows an application to set policy related to factory reset.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_FACTORY_RESET"
android:protectionLevel="internal|role" />
@@ -3609,6 +3691,8 @@
<!-- Allows an application to set policy related to the wallpaper.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_WALLPAPER"
android:protectionLevel="internal|role" />
@@ -3616,6 +3700,8 @@
<!-- Allows an application to set policy related to the usage of the contents of the screen.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SCREEN_CONTENT"
android:protectionLevel="internal|role" />
@@ -3623,6 +3709,8 @@
<!-- Allows an application to set policy related to system dialogs.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS"
android:protectionLevel="internal|role" />
@@ -3630,6 +3718,8 @@
<!-- Allows an application to set policy related to users running in the background.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_RUN_IN_BACKGROUND"
android:protectionLevel="internal|role" />
@@ -3637,6 +3727,8 @@
<!-- Allows an application to set policy related to printing.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PRINTING"
android:protectionLevel="internal|role" />
@@ -3645,12 +3737,16 @@
nearby streaming).
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION"
android:protectionLevel="internal|role" />
<!-- Allows an application to set policy related to <a
href="https://www.threadgroup.org">Thread</a> network.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
@FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK"
@@ -3658,6 +3754,8 @@
<!-- Allows an application to set policy related to sending assist content to a
privileged app such as the Assistant app.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
@FlaggedApi("android.app.admin.flags.assist_content_user_restriction_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ASSIST_CONTENT"
@@ -3666,6 +3764,8 @@
<!-- Allows an application to set policy related to windows.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_WINDOWS"
android:protectionLevel="internal|role" />
@@ -3673,6 +3773,8 @@
<!-- Allows an application to set policy related to locale.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCALE"
android:protectionLevel="internal|role" />
@@ -3680,6 +3782,8 @@
<!-- Allows an application to set policy related to autofill.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUTOFILL"
android:protectionLevel="internal|role" />
@@ -3687,6 +3791,8 @@
<!-- Allows an application to set policy related to users.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_USERS"
android:protectionLevel="internal|role" />
@@ -3694,6 +3800,8 @@
<!-- Allows an application to set policy related to certificates.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_CERTIFICATES"
android:protectionLevel="internal|role" />
@@ -3701,6 +3809,8 @@
<!-- Allows an application to set policy related to override APNs.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_OVERRIDE_APN"
android:protectionLevel="internal|role" />
@@ -3708,6 +3818,8 @@
<!-- Allows an application to set policy related to security logging.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING"
android:protectionLevel="internal|role" />
@@ -3723,6 +3835,8 @@
<!-- Allows an application to set policy related to system updates.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES"
android:protectionLevel="internal|role" />
@@ -3730,6 +3844,8 @@
<!-- Allows an application query system updates.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES"
android:protectionLevel="internal|role" />
@@ -3737,6 +3853,8 @@
<!-- Allows an application to set policy related to private DNS.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PRIVATE_DNS"
android:protectionLevel="internal|role" />
@@ -3744,6 +3862,8 @@
<!-- Allows an application to set policy related to settings.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SETTINGS"
android:protectionLevel="internal|role" />
@@ -3751,17 +3871,24 @@
<!-- Allows an application to set policy related to network logging.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_NETWORK_LOGGING"
android:protectionLevel="internal|role" />
- <!-- Allows an application to set policy related to usb data signalling.-->
+ <!-- Allows an application to set policy related to usb data signalling.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING"
android:protectionLevel="internal|role" />
<!-- Allows an application to set policy related to suspending personal apps.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SUSPEND_PERSONAL_APPS"
android:protectionLevel="internal|role" />
@@ -3769,13 +3896,17 @@
<!-- Allows an application to set policy related to keeping uninstalled packages.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEEP_UNINSTALLED_PACKAGES"
android:protectionLevel="internal|role" />
<!-- Allows an application to manage policy related to accessibility.
- <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
- APIs protected by this permission on users different to the calling user.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to
+ call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACCESSIBILITY"
android:protectionLevel="internal|role" />
@@ -3783,6 +3914,8 @@
<!-- Allows an application to manage policy related to common criteria mode.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE"
android:protectionLevel="internal|role" />
@@ -3790,6 +3923,8 @@
<!-- Allows an application to manage policy related to metered data.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_METERED_DATA"
android:protectionLevel="internal|role" />
@@ -3797,6 +3932,8 @@
<!-- Allows an application to set a network-independent global HTTP proxy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROXY"
android:protectionLevel="internal|role" />
@@ -3804,6 +3941,8 @@
<!-- Allows an application to request bugreports with user consent.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_BUGREPORT"
android:protectionLevel="internal|role" />
@@ -3811,6 +3950,8 @@
<!-- Allows an application to manage policy related to application user data.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_USER_DATA"
android:protectionLevel="internal|role" />
@@ -3819,6 +3960,8 @@
permission.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK"
android:protectionLevel="internal|role" />
@@ -3834,6 +3977,8 @@
<!-- Allows an application to manage policy related to system apps.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_APPS"
android:protectionLevel="internal|role" />
@@ -3841,16 +3986,23 @@
<!-- Allows an application to manage policy related to wiping data.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIPE_DATA"
android:protectionLevel="internal|role" />
<!-- Allows an application to manage policy related to the Memory Tagging Extension (MTE).
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MTE"
android:protectionLevel="internal|role" />
- <!-- Allows an application to manage policy related to device identifiers. -->
+ <!-- Allows an application to manage policy related to device identifiers.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS"
android:protectionLevel="internal|role" />
@@ -3863,24 +4015,33 @@
<!-- Allows an application to set policy related to subscriptions downloaded by an admin.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
- APIs protected by this permission on users different to the calling user.
- @FlaggedApi("android.app.admin.flags.esim_management_enabled") -->
+ APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ @FlaggedApi("android.app.admin.flags.esim_management_enabled")
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS"
android:protectionLevel="internal|role" />
<!-- Allows an application to manage policy related to block package uninstallation.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
@FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL"
android:protectionLevel="internal|role" />
<!-- Allows an application to manage policy related to camera toggle.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
@FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE"
android:protectionLevel="internal|role" />
<!-- Allows an application to manage policy related to microphone toggle.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
@FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE"
@@ -3889,16 +4050,21 @@
<!-- Allows an application to set device policies outside the current user
that are critical for securing data within the current user.
<p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
- permissions across all users on the device provided they are required for securing data
- within the current user.-->
+ permissions across all users on the device provided they are required for securing data
+ within the current user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL"
android:protectionLevel="internal|role" />
<!-- Allows an application to set device policies outside the current user
that are required for securing device ownership without accessing user data.
<p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
- permissions across all users on the device provided they do not grant access to user
- data. -->
+ permissions across all users on the device provided they do not grant access to user data.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS"
android:protectionLevel="internal|role" />
@@ -3906,7 +4072,10 @@
<p>Fuller form of {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS}
that removes the restriction on accessing user data.
<p>Holding this permission allows the use of any other held MANAGE_DEVICE_POLICY_*
- permissions across all users on the device.-->
+ permissions across all users on the device.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL"
android:protectionLevel="internal|role" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 704d442..18425fe 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privaat ruimte"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Gemeenskaplik"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privaat ruimte"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitiewe kennisgewinginhoud is versteek"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Appinhoud is weens sekuriteit van skermdeling verberg"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index d1e18da..965160e 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"የግል ቦታ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"አባዛ"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"የጋራ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"የግል ቦታ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"አደገኛ የማሳወቂያ ይዘት ተደብቋል"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ለደኅንነት ሲባል የመተግበሪያ ይዘት ከማያ ገጽ ማጋራት ተደብቋል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 5ef18af..3e396e0 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -2411,8 +2411,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"المساحة الخاصة"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"نسخة طبق الأصل"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ملف شخصي مشترك"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"المساحة الخاصّة"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"تم إخفاء المحتوى الحساس في الإشعار"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"تم إخفاء محتوى التطبيق بعد تفعيل ميزة \"مشاركة الشاشة\" للحفاظ على أمانك"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 5443f12..5f9f16a 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1865,7 +1865,7 @@
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
<string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"অজ্ঞাত প\'ৰ্ট্ৰেইট"</string>
- <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"অজ্ঞাত লেণ্ডস্কেইপ"</string>
+ <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"অজ্ঞাত লেণ্ডস্কে’প"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"বাতিল কৰা হ’ল"</string>
<string name="write_fail_reason_cannot_write" msgid="432118118378451508">"সমল লিখাত আসোঁৱাহ"</string>
<string name="reason_unknown" msgid="5599739807581133337">"অজ্ঞাত"</string>
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"প্ৰাইভেট স্পে’চ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ক্ল’ন"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"সম্প্ৰদায়ৰ সৈতে জড়িত"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"প্ৰাইভেট স্পে’চ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"সংবেদনশীল জাননী লুকুওৱা হৈছে"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"সুৰক্ষাৰ বাবে এপৰ সমল স্ক্ৰীণ শ্বেয়াৰ কৰাৰ পৰা লুকুৱাই ৰখা হৈছে"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index b9ec742..c4327e7 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Məxfi sahə"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Kommunal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Şəxsi sahə"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Həssas bildiriş kontenti gizlədildi"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Güvənlik üçün tətbiq kontenti ekran paylaşımından gizlədildi"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 858075b..2b81e1c 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatan prostor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klonirano"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Zajedničko"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privatan prostor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Osetljiv sadržaj obaveštenja je skriven"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je skriven za deljenje sadržaja ekrana zbog bezbednosti"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 2739cb2..7d1f6be 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Прыватная прастора"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Супольны"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Прыватная прастора"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Канфідэнцыяльнае змесціва ў апавяшчэннях схавана"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Змесціва праграмы выключана з абагульвання экрана ў мэтах бяспекі"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0d4cadc..a2f0364 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Частно пространство"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клониране"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Общи"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Частно пространство"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Деликатното съдържание в известието е скрито"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Съдържанието на приложението е скрито от функцията за споделяне на екрана от съображения за сигурност"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 03fba4b..e21b5c0 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"প্রাইভেট স্পেস"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ক্লোন"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"কমিউনাল"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"প্রাইভেট স্পেস"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"সংবেদনশীল বিজ্ঞপ্তির কন্টেন্ট লুকানো আছে"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"নিরাপত্তার জন্য স্ক্রিন শেয়ার করা থেকে লুকানো অ্যাপের কন্টেন্ট"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 6ce10c0..2f285f1 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatni prostor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Opće"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privatni prostor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sakriven je osjetljiv sadržaj obavještenja"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je sakriven od dijeljenja ekrana radi sigurnosti"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4b1af34..48ba090c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espai privat"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Comunitari"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espai privat"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"S\'ha amagat contingut sensible de les notificacions"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contingut de l\'aplicació amagat de la compartició de pantalla per motius de seguretat"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index cc4bd3c..64ccaf5 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Soukromý prostor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Komunální"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Soukromý prostor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Obsah citlivých oznámení je skrytý"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikace je z bezpečnostních důvodů při sdílení obrazovky skryt"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 665ea17..a499afc 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Fælles"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privat område"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Følsomt indhold i notifikationen er skjult"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Af sikkerhedsmæssige årsager vises appindhold ikke ved skærmdeling"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index cd637e1..464a5373 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Vertrauliches Profil"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Gemeinsam genutzt"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Vertrauliches Profil"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Vertrauliche Benachrichtigungsinhalte ausgeblendet"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App-Inhalte werden aus Sicherheitsgründen bei der Bildschirmfreigabe ausgeblendet"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 09ecc2c..98ce03c 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ιδιωτικός χώρος"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Κλώνος"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Κοινόχρηστο"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Ιδιωτικός χώρος"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Έγινε απόκρυψη της ειδοποίησης ευαίσθητου περιεχομένου"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Για λόγους ασφάλειας, έγινε απόκρυψη του περιεχομένου της εφαρμογής από την κοινή χρήση οθόνης"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 20e391d..1d2fc4d 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Private space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 7f33f6a..c03bb3c 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Private space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index b7fedbe..436d7ae 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Private space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index b83a7cf..d34ed3f6e 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Private space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index d358e5e..c2c107c 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Private space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 45ea7ee..df7deac 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espacio privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Compartido"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espacio privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Se ocultó contenido sensible de la notificación"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Se ocultó el contenido de la app durante el uso compartido de la pantalla por motivos de seguridad"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 19c5f84..e22430f 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -717,7 +717,7 @@
<string name="face_acquired_too_right" msgid="6245286514593540859">"Mueve el teléfono hacia la izquierda"</string>
<string name="face_acquired_too_left" msgid="9201762240918405486">"Mueve el teléfono hacia la derecha"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Mira de forma más directa al dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="1057966913397548150">"No se puede detectar tu cara. Sujeta el teléfono a la altura de los ojos."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"No se detecta tu cara. Sujeta el teléfono a la altura de los ojos."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"El teléfono se mueve demasiado. Mantenlo quieto."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Vuelve a registrar tu cara."</string>
<string name="face_acquired_too_different" msgid="4505278456634706967">"Cara no reconocida. Inténtalo de nuevo."</string>
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espacio privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Común"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espacio privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Contenido sensible de la notificación oculto"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenido de la aplicación oculto en pantalla compartida por motivos de seguridad"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 46c7341..979079d 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privaatne ruum"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Ühine"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privaatne ruum"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Märguande delikaatne sisu peideti"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Rakenduse sisu on ekraani jagamises turvalisuse huvides peidetud"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 3c47f68..06855f5 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -190,7 +190,7 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> gehiegi ezabatzen saiatu zara."</string>
<string name="low_memory" product="tablet" msgid="5557552311566179924">"Tabletaren memoria beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string>
<string name="low_memory" product="watch" msgid="3479447988234030194">"Erlojuaren memoria beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string>
- <string name="low_memory" product="tv" msgid="6663680413790323318">"Android TV gailuaren memoria beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string>
+ <string name="low_memory" product="tv" msgid="6663680413790323318">"Android TV gailuko biltegia beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string>
<string name="low_memory" product="default" msgid="2539532364144025569">"Telefonoaren memoria beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string>
<string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoritate ziurtagiri-emaile bat dago instalatuta}other{Autoritate ziurtagiri-emaile bat baino gehiago daude instalatuta}}"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Hirugarren alderdi ezezagun baten arabera"</string>
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Eremu pribatua"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klona"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Partekatua"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Eremu pribatua"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Jakinarazpenaren kontuzko edukia ezkutatu da"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Aplikazioko edukia ezkutatu egin da pantaila partekatzeko eginbidetik, segurtasuna bermatzeko"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 3c50b07..b0e6e6e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"فضای خصوصی"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"همسانهسازی"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"همگانی"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"فضای خصوصی"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"محتوای اعلان حساس پنهان شده است"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"بهدلایل امنیتی، محتوای برنامه از دید همرسانی صفحهنمایش پنهان شد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 0e159f2..7e2fa9c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Yksityinen tila"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klooni"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Yhteinen"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Yksityinen tila"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Arkaluontoisen ilmoituksen sisältö piilotettu"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sovelluksen sisältö piilotettu näytön jakamiselta turvallisuussyistä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 7fca5e6..a21aefb 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espace privé"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Commun"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espace privé"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Le contenu confidentiel de la notification est masqué"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'application est masqué du Partage d\'écran par mesure de sécurité"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index e08f426..486124e 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espace privé"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Commun"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espace privé"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Le contenu sensible de la notification a été masqué"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'appli est masqué lors du partage d\'écran pour des raisons de sécurité"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 1eec828..9994a3e 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espazo privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clonado"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Compartido"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espazo privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Contido confidencial da notificación oculto"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Por motivos de seguranza, ocultouse o contido da aplicación para que no se mostre na pantalla compartida"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 303f001..3206242 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ખાનગી સ્પેસ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ક્લોન"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"કૉમ્યુનલ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ખાનગી સ્પેસ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"સંવેદનશીલ માહિતીવાળા નોટિફિકેશનનું કન્ટેન્ટ છુપાવ્યું"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"સુરક્ષા માટે સ્ક્રીન શેર કરતી વખતે ઍપનું કન્ટેન્ટ છુપાવેલું છે"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 14d2bf7..f7ae13e 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"प्राइवेट स्पेस"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"कम्यूनिटी"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"प्राइवेट स्पेस"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"संवेदनशील जानकारी वाली सूचना का कॉन्टेंट छिपा है"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रीन शेयर करने के दौरान सुरक्षा के लिए, ऐप्लिकेशन का कॉन्टेंट छिपाया गया"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e69a59d..f6f7e8b 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatni prostor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Zajedničko"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privatni prostor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Skriven je osjetljiv sadržaj obavijesti"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije sakriven je od dijeljenja zaslona radi sigurnosti"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index f1ff236..5162616 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privát terület"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klón"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Közös"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privát terület"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Bizalmas értesítéstartalom elrejtve"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"A biztonság érdekében a képernyőmegosztástól elrejtett alkalmazástartalom"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 40812068..f2b6932 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Մասնավոր տարածք"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Կլոն"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Ընդհանուր"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Մասնավոր տարածք"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Ծանուցման զգայուն բովանդակությունը թաքցված է"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Անվտանգության նկատառումներից ելնելով՝ հավելվածի բովանդակությունը թաքցվել է էկրանի ցուցադրումից"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 866e946..d1a20f34 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang privasi"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umum"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Ruang privasi"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Konten notifikasi sensitif disembunyikan"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Konten aplikasi disembunyikan dari berbagi layar untuk alasan keamanan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 76ba64b..c8da948 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Leynirými"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Afrit"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Sameiginlegt"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Leynirými"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Viðkvæmt tilkynningaefni falið"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Efni forrits falið í skjádeilingu af öryggisástæðum"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 5e87dce..403c522 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Spazio privato"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Condiviso"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Spazio privato"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Contenuti sensibili della notifica nascosti"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenuti dell\'app nascosti dalla condivisione schermo per sicurezza"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 439565d..21e9293 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -2039,7 +2039,7 @@
<string name="pin_specific_target" msgid="7824671240625957415">"הצמדה של <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"ביטול הצמדה"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"ביטול ההצמדה של <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="app_info" msgid="6113278084877079851">"פרטי אפליקציה"</string>
+ <string name="app_info" msgid="6113278084877079851">"פרטי האפליקציה"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"תהליך ההדגמה מתחיל…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"מתבצע איפוס של המכשיר…"</string>
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"המרחב הפרטי"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"שכפול"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"שיתופי"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"המרחב הפרטי"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"יש תוכן רגיש בהתראה שהוסתר"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"תוכן האפליקציה מוסתר משיתוף המסך מטעמי אבטחה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index fcaef68..149f3cd 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"プライベート スペース"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共用"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"プライベート スペース"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"プライベートな通知内容は表示されません"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"セキュリティ上、画面共有ではアプリの内容は非表示となります"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 2b98c58..ee1e89d 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"კერძო სივრცე"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"კლონის შექმნა"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"საერთო"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"კერძო სივრცე"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"სენსიტიური შეტყობინების კონტენტი დამალულია"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ეკრანის გაზიარებიდან აპის კონტენტი დამალულია უსაფრთხოების მიზნით"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 6e9eb12..63457e0 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Құпия кеңістік"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Жалпы"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Құпия кеңістік"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Хабарландырудың құпия контенті жасырылған."</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Қауіпсіздік мақсатында қолданба контенті экранды көрсету кезінде жасырылды."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 70f59c1..7294d4b 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"លំហឯកជន"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ក្លូន"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ទូទៅ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"លំហឯកជន"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"បានលាក់ខ្លឹមសារជូនដំណឹងដែលមានលក្ខណៈរសើប"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"បានលាក់ខ្លឹមសារកម្មវិធីពីការបង្ហាញអេក្រង់ដើម្បីសុវត្ថិភាព"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index f22c43a..3d7c782 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ಕ್ಲೋನ್"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ಸಮುದಾಯ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"ಸೂಕ್ಷ್ಮ ನೋಟಿಫಿಕೇಶನ್ ಕಂಟೆಂಟ್ ಅನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ಭದ್ರತೆಗಾಗಿ ಸ್ಕ್ರೀನ್ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯಲ್ಲಿ ಆ್ಯಪ್ ಕಂಟೆಂಟ್ ಅನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 99b8715..d815fe8 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"비공개 스페이스"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"클론"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"공동"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"비공개 스페이스"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"민감한 알림 콘텐츠 숨김"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"보안을 위해 화면 공유에서 앱 콘텐츠가 숨겨집니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 427010b..3cdf3ca 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Жеке мейкиндик"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Жалпы"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Жеке мейкиндик"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Купуя билдирменин мазмуну жашырылган"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Коопсуздук үчүн колдонмодогу контент бөлүшүлгөн экрандан жашырылды"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 4682bb0..80e09a6 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ພື້ນທີ່ສ່ວນບຸກຄົນ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ໂຄລນ"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ສ່ວນກາງ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ພື້ນທີ່ສ່ວນບຸກຄົນ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"ເນື້ອຫາການແຈ້ງເຕືອນທີ່ລະອຽດອ່ອນເຊື່ອງຢູ່"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ເນື້ອຫາແອັບຖືກເຊື່ອງໄວ້ຈາກການແບ່ງປັນໜ້າຈໍເພື່ອຄວາມປອດໄພ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 6fbb9b8..b237241 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privati erdvė"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klonuoti"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Bendruomenės"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privati erdvė"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Neskelbtinos informacijos pranešimo turinys paslėptas"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Programos turinys paslėptas bendrinant ekraną saugumo sumetimais"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 0bea4ff..cc902cd 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privātā telpa"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klons"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Kopīgs"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privātā telpa"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitīvs paziņojuma saturs ir paslēpts"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Drošības nolūkos lietotnes saturs kopīgotajā ekrānā ir paslēpts"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index d7a6dd2..b61b817 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватен простор"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клониран профил"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Профил на заедницата"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Приватен простор"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Содржината на чувствителните известувања е скриена"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Од безбедносни причини, содржините на апликацијата се скриени од споделувањето екран"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 4023336..9906470 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"സ്വകാര്യ സ്പേസ്"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ക്ലോൺ ചെയ്യുക"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"കമ്മ്യൂണൽ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"സ്വകാര്യ സ്പേസ്"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"സൂക്ഷ്മമായി കൈകാര്യം ചെയ്യേണ്ട അറിയിപ്പ് ഉള്ളടക്കം മറച്ചിരിക്കുന്നു"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ആപ്പ് ഉള്ളടക്കം, അതിന്റെ സുരക്ഷയ്ക്കായി സ്ക്രീൻ പങ്കിടലിൽ നിന്ന് മറച്ചിരിക്കുന്നു"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 9aa18e2..22f8f15 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Хаалттай орон зай"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Нийтийн"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Хаалттай орон зай"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Эмзэг мэдэгдлийн контентыг нуусан"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Аюулгүй байдлын улмаас аппын контентыг дэлгэц хуваалцахаас нуусан"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a115e2c..36d0bba 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"खाजगी स्पेस"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"सामुदायिक"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"खाजगी स्पेस"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"संवेदनशील नोटिफिकेशनचा आशय लपवलेला आहे"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रीन शेअर करताना सुरक्षेसाठी अॅपमधील आशय लपवला आहे"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 2fa571c..c215f62 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang persendirian"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umum"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Ruang privasi"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Kandungan pemberitahuan yang sensitif disembunyikan"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Kandungan apl disembunyikan daripada perkongsian skrin untuk keselamatan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 364a7b1..f030ef2 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"သီးသန့်နေရာ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ပုံတူပွားရန်"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"အများသုံး"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"သီးသန့်နေရာ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"သတိထားရမည့် အကြောင်းကြားချက်ပါ အချက်အလက်ကို ဖျောက်ထားသည်"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"အက်ပ်အကြောင်းအရာသည် လုံခြုံရေးအတွက် မျက်နှာပြင် မျှဝေခြင်းမှ ဖျောက်ထားသည်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e2de428..116c586 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Felles"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privat område"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitivt varselinnhold er skjult"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av sikkerhetsgrunner er appinnholdet skjult for skjermdelingen"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 8d5f560..a202d4c 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"निजी स्पेस"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"सामुदायिक"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"निजी स्पेस"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"संवेदनशील सूचनासम्बन्धी सामग्री लुकाइएको छ"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रिन सेयर गर्दा सुरक्षाका लागि एपमा भएको सामग्री लुकाइएको छ"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5bc6c44..51d8959 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privégedeelte"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Gemeenschappelijk"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privégedeelte"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Content van gevoelige meldingen verborgen"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App-content verborgen voor scherm delen vanwege beveiligingsrisico\'s"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 4c7868d..90ab620 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"କ୍ଲୋନ"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"କମ୍ୟୁନାଲ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"ସମ୍ୱେଦନଶୀଳ ବିଜ୍ଞପ୍ତି ବିଷୟବସ୍ତୁକୁ ଲୁଚାଯାଇଛି"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ସୁରକ୍ଷା ପାଇଁ ସ୍କ୍ରିନ ସେୟାରରୁ ଆପ ବିଷୟବସ୍ତୁକୁ ଲୁଚାଯାଇଛି"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 38780b6..de91ea7 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ਕਲੋਨ"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ਭਾਈਚਾਰਕ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"ਲੁਕੀ ਹੋਈ ਸੰਵੇਦਨਸ਼ੀਲ ਸੂਚਨਾ ਸਮੱਗਰੀ"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ਐਪ ਸਮੱਗਰੀ ਨੂੰ ਸੁਰੱਖਿਆ ਲਈ ਸਕ੍ਰੀਨ ਸਾਂਝਾਕਰਨ ਤੋਂ ਲੁਕਾਇਆ ਗਿਆ ਹੈ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 95e1a30..d9a95b8 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Przestrzeń prywatna"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Wspólny"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Przestrzeń prywatna"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Treść poufnego powiadomienia została ukryta"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ze względów bezpieczeństwa zawartość aplikacji jest niewidoczna podczas udostępniania ekranu"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index c9d36b1..cd3a7c5 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Público"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espaço privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo de notificação sensível oculto"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo do app oculto no compartilhamento de tela por motivos de segurança"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f1b2bd0..d8fe4fe 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -733,7 +733,7 @@
<skip />
<string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Não é possível criar o seu modelo de rosto. Tente novamente."</string>
<string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Óculos escuros detetados. O seu rosto tem de estar completamente visível."</string>
- <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Máscara detetada. Todo o rosto tem de estar visível"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Cobertura facial detetada. O seu rosto tem de estar completamente visível."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Não pode validar o rosto. Hardware não disponível."</string>
@@ -1292,7 +1292,7 @@
<string name="android_upgrading_complete" msgid="409800058018374746">"A concluir o arranque."</string>
<string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Premiu o botão ligar/desligar. Geralmente, esta ação desliga o ecrã.\n\nExperimente tocar levemente ao configurar a sua impressão digital."</string>
<string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Para terminar, desligue o ecrã"</string>
- <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Desligar"</string>
+ <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Desativar"</string>
<string name="fp_power_button_bp_title" msgid="5585506104526820067">"Continuar a validar a impressão digital?"</string>
<string name="fp_power_button_bp_message" msgid="2983163038168903393">"Premiu o botão ligar/desligar. Geralmente, esta ação desliga o ecrã.\n\nExperimente tocar levemente para validar a sua impressão digital."</string>
<string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"Desligar ecrã"</string>
@@ -1438,7 +1438,7 @@
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"A app <xliff:g id="NAME">%s</xliff:g> sobrepõe-se a outras aplicações"</string>
<string name="alert_windows_notification_title" msgid="6331662751095228536">"O <xliff:g id="NAME">%s</xliff:g> sobrepõe-se a outras app"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"Se não quer que a app <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
- <string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Desligar"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Desativar"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"A verificar o <xliff:g id="NAME">%s</xliff:g>…"</string>
<string name="ext_media_checking_notification_message" msgid="2231566971425375542">"A rever o conteúdo atual…"</string>
<string name="ext_media_checking_notification_message" product="tv" msgid="7986154434946021415">"A analisar o armazenamento de multimédia"</string>
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Comum"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espaço privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo das notificações sensíveis ocultado"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo da app ocultado da partilha de ecrã por motivos de segurança"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index c9d36b1..cd3a7c5 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Público"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espaço privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo de notificação sensível oculto"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo do app oculto no compartilhamento de tela por motivos de segurança"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index e14aec7..d43556d 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Spațiu privat"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clonă"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Comun"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Spațiu privat"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Conținutul sensibil din notificări a fost ascuns"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conținutul aplicației este ascuns de permiterea accesului la ecran din motive de securitate"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 79b0daa..16ddae8 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Частное пространство"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клонированный"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Совместный"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Частное пространство"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Конфиденциальная информация в уведомлении скрыта"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Содержимое приложения исключено из демонстрации экрана в целях безопасности."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 1e69e0b..4f6e756 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"රහසිගත අවකාශය"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ක්ලෝන කරන්න"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"වාර්ගික"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"රහසිගත අවකාශය"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"සංවේදී දැනුම්දීම් අන්තර්ගතය සැඟවී ඇත"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ආරක්ෂාව සඳහා යෙදුම් අන්තර්ගතය තිරය බෙදා ගැනීමෙන් සඟවා ඇත"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c7ca9f4..aeea7b6 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -2040,7 +2040,7 @@
<string name="pin_specific_target" msgid="7824671240625957415">"Pripnúť <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"Uvoľniť"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Odopnúť <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="app_info" msgid="6113278084877079851">"Info o aplikácii"</string>
+ <string name="app_info" msgid="6113278084877079851">"Informácie o aplikácii"</string>
<string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Spúšťa sa ukážka…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Resetuje sa zariadenie…"</string>
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Súkromný priestor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Spoločný"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Súkromný priestor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Obsah citlivého upozornenia je skrytý"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikácie bol na účely zabezpečenia skrytý v zdieľaní obrazovky"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4f23a54..d3ce57c 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Zasebni prostor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Skupno"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Zasebni prostor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Občutljiva vsebina obvestila je bila skrita"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Pri deljenju zaslona je vsebina aplikacije skrita zaradi varnosti"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index c49402b..de02100 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Hapësira private"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"I përbashkët"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Hapësira private"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Përmbajtjet delikate të njoftimeve janë fshehur"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Përmbajtja e aplikacionit është fshehur nga ndarja e ekranit për arsye sigurie"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 2b3f75a..f200ac1 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватан простор"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клонирано"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Заједничко"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Приватан простор"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Осетљив садржај обавештења је скривен"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Садржај апликације је скривен за дељење садржаја екрана због безбедности"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 2833381..589414d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -2038,7 +2038,7 @@
<string name="pin_specific_target" msgid="7824671240625957415">"Fäst <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"Lossa"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Lossa <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="app_info" msgid="6113278084877079851">"Info om appen"</string>
+ <string name="app_info" msgid="6113278084877079851">"Appinformation"</string>
<string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Demo startas …"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Enheten återställs …"</string>
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klona"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Allmän"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privat område"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Känsligt aviseringsinnehåll dolt"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av säkerhetsskäl döljs appinnehållet vid skärmdelning"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d3af99f..4b50cb7 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Sehemu ya faragha"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nakala"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Wasifu wa pamoja"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Sehemu ya faragha"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Maudhui nyeti kwenye arifa yamefichwa"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Maudhui ya programu yamefichwa ili yasionekane kwenye skrini ya pamoja kwa sababu za kiusalama"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 37abcef..6ad8f59 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ரகசிய இடம்"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"குளோன்"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"பொது"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ரகசிய இடம்"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"உணர்வுபூர்வமான அறிவிப்பு உள்ளடக்கம் மறைக்கப்பட்டது"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"பாதுகாப்பிற்காக, திரைப் பகிர்வில் இருந்து ஆப்ஸ் உள்ளடக்கம் மறைக்கப்பட்டுள்ளது"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 2766248..91f9ef2 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ప్రైవేట్ స్పేస్"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"క్లోన్"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"కమ్యూనల్"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ప్రైవేట్ స్పేస్"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"గోప్యమైన నోటిఫికేషన్ కంటెంట్ దాచబడింది"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"సెక్యూరిటీ కోసం స్క్రీన్ షేర్ నుండి యాప్ కంటెంట్ దాచబడింది"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 1f2a091..eb102fc 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"พื้นที่ส่วนตัว"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"โคลน"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ส่วนกลาง"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"พื้นที่ส่วนตัว"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"เนื้อหาการแจ้งเตือนที่ละเอียดอ่อนซ่อนอยู่"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ซ่อนเนื้อหาแอปจากการแชร์หน้าจอเพื่อความปลอดภัย"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 7bce4b7..de499d34 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Pribadong space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Pribadong space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Nakatago ang content ng sensitibong notification"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nakatago ang content ng app mula sa pagbabahagi ng screen para sa seguridad"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index cbfb770..7dab236 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Özel alan"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Paylaşılan"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Özel alan"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Hassas bildirim içerikleri gizlendi"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Uygulama içerikleri, güvenlik nedeniyle ekran paylaşımında gizlendi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5266acd..22c7272 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватний простір"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Копія профілю"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Спільний профіль"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Приватний простір"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Чутливий вміст сповіщення приховано"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"З міркувань безпеки вміст додатка приховано під час показу екрана"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 2fe52f8..0d878c9 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"پرائیویٹ اسپیس"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"کلون"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"کمیونل"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"پرائیویٹ اسپیس"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"حساس اطلاعی مواد چھپا ہوا ہے"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"سیکیورٹی کے مد نظر ایپ کا مواد اسکرین کے اشتراک سے چھپا ہوا ہے"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d40f383..fc5d8ee 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Maxfiy makon"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nusxalash"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umumiy"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Maxfiy makon"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Bildirishnomadagi maxfiy axborot berkitildi"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ekran namoyishida xavfsizlik maqsadida ilova kontenti berkitildi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 1051cda..4619be3 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Không gian riêng tư"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nhân bản"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Dùng chung"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Không gian riêng tư"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Đã ẩn nội dung thông báo nhạy cảm"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nội dung ứng dụng bị ẩn khỏi tính năng chia sẻ màn hình vì lý do bảo mật"</string>
diff --git a/core/res/res/values-w204dp-round-watch/dimens_material.xml b/core/res/res/values-w204dp-round-watch/dimens_material.xml
new file mode 100644
index 0000000..c07d5c4
--- /dev/null
+++ b/core/res/res/values-w204dp-round-watch/dimens_material.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <dimen name="screen_percentage_05">10.2dp</dimen>
+ <dimen name="screen_percentage_10">20.4dp</dimen>
+ <dimen name="screen_percentage_15">30.6dp</dimen>
+</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d16a353..a6c62dc 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -581,7 +581,7 @@
<string name="permlab_changeTetherState" msgid="9079611809931863861">"更改网络共享连接"</string>
<string name="permdesc_changeTetherState" msgid="3025129606422533085">"允许应用更改绑定网络连接的状态。"</string>
<string name="permlab_accessWifiState" msgid="5552488500317911052">"查看WLAN连接"</string>
- <string name="permdesc_accessWifiState" msgid="6913641669259483363">"允许该应用查看WLAN网络的相关信息,例如是否启用了WLAN以及连接的WLAN设备的名称。"</string>
+ <string name="permdesc_accessWifiState" msgid="6913641669259483363">"允许该应用查看 WLAN 网络的相关信息,例如是否启用了 WLAN 以及连接的 WLAN 设备的名称。"</string>
<string name="permlab_changeWifiState" msgid="7947824109713181554">"连接WLAN网络和断开连接"</string>
<string name="permdesc_changeWifiState" msgid="7170350070554505384">"允许该应用与WLAN接入点建立和断开连接,以及更改WLAN网络的设备配置。"</string>
<string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"允许接收WLAN多播"</string>
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"私密空间"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"克隆"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共用"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"私密空间"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"已隐藏敏感通知内容"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"为安全起见而在屏幕共享画面中处于隐藏状态的应用内容"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 672a638..f9b10a2 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"私人空間"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共用"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"私人空間"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"已隱藏敏感通知內容"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"為安全起見,應用程式內容已從分享螢幕畫面隱藏"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 8a224ed..4dce59a 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"私人空間"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共通"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"私人空間"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"系統已隱藏含有私密資訊的通知內容"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"為安全起見,分享螢幕畫面未顯示應用程式內容"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 27bd3c9..60cb31b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Indawo engasese"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Yenza i-Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Okomphakathi"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Indawo engasese"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Okuqukethwe kwesaziso esizwelayo kufihliwe"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Okuqukethwe kwe-app kufihliwe kusuka ekwabelaneni kwesikrini ngokuvikelwa"</string>
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
index 94c281f..290fefa 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
@@ -1394,10 +1394,16 @@
primaryBounds = mProperties.mIsReversedLayout ? boundsBottom : boundsTop;
secondaryBounds = mProperties.mIsReversedLayout ? boundsTop : boundsBottom;
}
- t.setWindowCrop(mPrimaryVeil, primaryBounds.width(), primaryBounds.height());
- t.setWindowCrop(mSecondaryVeil, secondaryBounds.width(), secondaryBounds.height());
- t.setPosition(mPrimaryVeil, primaryBounds.left, primaryBounds.top);
- t.setPosition(mSecondaryVeil, secondaryBounds.left, secondaryBounds.top);
+ if (mPrimaryVeil != null) {
+ t.setWindowCrop(mPrimaryVeil, primaryBounds.width(), primaryBounds.height());
+ t.setPosition(mPrimaryVeil, primaryBounds.left, primaryBounds.top);
+ t.setVisibility(mPrimaryVeil, !primaryBounds.isEmpty());
+ }
+ if (mSecondaryVeil != null) {
+ t.setWindowCrop(mSecondaryVeil, secondaryBounds.width(), secondaryBounds.height());
+ t.setPosition(mSecondaryVeil, secondaryBounds.left, secondaryBounds.top);
+ t.setVisibility(mSecondaryVeil, !secondaryBounds.isEmpty());
+ }
}
private static float[] colorToFloatArray(@NonNull Color color) {
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index aafb2e1..150a6e6 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -84,7 +84,7 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovat"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina byla zavřena."</string>
- <string name="restart_button_description" msgid="4564728020654658478">"Klepnutím tuto aplikaci kvůli lepšímu zobrazení restartujete"</string>
+ <string name="restart_button_description" msgid="4564728020654658478">"Klepnutím tuto aplikaci restartujete kvůli lepšímu zobrazení"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Změnit v Nastavení poměr stran této aplikace"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Změnit poměr stran"</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s fotoaparátem?\nKlepnutím vyřešíte"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 9f03d8b..6005be4 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -85,7 +85,7 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen er avvist."</string>
<string name="restart_button_description" msgid="4564728020654658478">"Trykk for å starte denne appen på nytt og få en bedre visning"</string>
- <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Endre høyde/bredde-forholdet for denne appen i innstillingene"</string>
+ <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Endre høyde/bredde-forholdet for denne appen i Innstillinger"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Endre høyde/bredde-forholdet"</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du kameraproblemer?\nTrykk for å tilpasse"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ble ikke problemet løst?\nTrykk for å gå tilbake"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 32873d9..81e7d1f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -602,7 +602,7 @@
List<Bubble> removedBubbles = filterAllBubbles(bubble ->
userId == bubble.getUser().getIdentifier());
for (Bubble b : removedBubbles) {
- doRemove(b.getKey(), Bubbles.DISMISS_USER_REMOVED);
+ doRemove(b.getKey(), Bubbles.DISMISS_USER_ACCOUNT_REMOVED);
}
if (!removedBubbles.isEmpty()) {
dispatchPendingChanges();
@@ -678,7 +678,7 @@
|| reason == Bubbles.DISMISS_SHORTCUT_REMOVED
|| reason == Bubbles.DISMISS_PACKAGE_REMOVED
|| reason == Bubbles.DISMISS_USER_CHANGED
- || reason == Bubbles.DISMISS_USER_REMOVED;
+ || reason == Bubbles.DISMISS_USER_ACCOUNT_REMOVED;
int indexToRemove = indexForKey(key);
if (indexToRemove == -1) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 1d053f9..82af88d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -61,7 +61,7 @@
DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
- DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_REMOVED,
+ DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_ACCOUNT_REMOVED,
DISMISS_SWITCH_TO_STACK})
@Target({FIELD, LOCAL_VARIABLE, PARAMETER})
@interface DismissReason {
@@ -82,7 +82,7 @@
int DISMISS_PACKAGE_REMOVED = 13;
int DISMISS_NO_BUBBLE_UP = 14;
int DISMISS_RELOAD_FROM_DISK = 15;
- int DISMISS_USER_REMOVED = 16;
+ int DISMISS_USER_ACCOUNT_REMOVED = 16;
int DISMISS_SWITCH_TO_STACK = 17;
/** Returns a binder that can be passed to an external process to manipulate Bubbles. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 2234041..c2242a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -336,6 +336,11 @@
setTouching();
mStartPos = touchPos;
mMoving = false;
+ // This triggers initialization of things like the resize veil in preparation for
+ // showing it when the user moves the divider past the slop, and has to be done
+ // before onStartDragging() which starts the jank interaction tracing
+ mSplitLayout.updateDividerBounds(mSplitLayout.getDividerPosition(),
+ false /* shouldUseParallaxEffect */);
mSplitLayout.onStartDragging();
break;
case MotionEvent.ACTION_MOVE:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 3dcdc0b..4d597ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -99,10 +99,12 @@
private DragPositioningCallback mDragPositioningCallback;
private DragResizeInputListener mDragResizeListener;
private DragDetector mDragDetector;
-
+ private Runnable mCurrentViewHostRunnable = null;
private RelayoutParams mRelayoutParams = new RelayoutParams();
private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult =
new WindowDecoration.RelayoutResult<>();
+ private final Runnable mViewHostRunnable =
+ () -> updateViewHost(mRelayoutParams, null /* onDrawTransaction */, mResult);
private final Point mPositionInParent = new Point();
private HandleMenu mHandleMenu;
@@ -194,17 +196,88 @@
// position and crop are set.
final boolean shouldSetTaskPositionAndCrop = !DesktopModeStatus.isVeiledResizeEnabled()
&& mTaskDragResizer.isResizingOrAnimating();
- // Use |applyStartTransactionOnDraw| so that the transaction (that applies task crop) is
- // synced with the buffer transaction (that draws the View). Both will be shown on screen
- // at the same, whereas applying them independently causes flickering. See b/270202228.
- relayout(taskInfo, t, t, true /* applyStartTransactionOnDraw */,
- shouldSetTaskPositionAndCrop);
+ // For headers only (i.e. in freeform): use |applyStartTransactionOnDraw| so that the
+ // transaction (that applies task crop) is synced with the buffer transaction (that draws
+ // the View). Both will be shown on screen at the same, whereas applying them independently
+ // causes flickering. See b/270202228.
+ final boolean applyTransactionOnDraw =
+ taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM;
+ relayout(taskInfo, t, t, applyTransactionOnDraw, shouldSetTaskPositionAndCrop);
+ if (!applyTransactionOnDraw) {
+ t.apply();
+ }
}
void relayout(ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
Trace.beginSection("DesktopModeWindowDecoration#relayout");
+ if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ // The Task is in Freeform mode -> show its header in sync since it's an integral part
+ // of the window itself - a delayed header might cause bad UX.
+ relayoutInSync(taskInfo, startT, finishT, applyStartTransactionOnDraw,
+ shouldSetTaskPositionAndCrop);
+ } else {
+ // The Task is outside Freeform mode -> allow the handle view to be delayed since the
+ // handle is just a small addition to the window.
+ relayoutWithDelayedViewHost(taskInfo, startT, finishT, applyStartTransactionOnDraw,
+ shouldSetTaskPositionAndCrop);
+ }
+ Trace.endSection();
+ }
+
+ /** Run the whole relayout phase immediately without delay. */
+ private void relayoutInSync(ActivityManager.RunningTaskInfo taskInfo,
+ SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
+ boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
+ // Clear the current ViewHost runnable as we will update the ViewHost here
+ clearCurrentViewHostRunnable();
+ updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT, applyStartTransactionOnDraw,
+ shouldSetTaskPositionAndCrop);
+ if (mResult.mRootView != null) {
+ updateViewHost(mRelayoutParams, startT, mResult);
+ }
+ }
+
+ /**
+ * Clear the current ViewHost runnable - to ensure it doesn't run once relayout params have been
+ * updated.
+ */
+ private void clearCurrentViewHostRunnable() {
+ if (mCurrentViewHostRunnable != null) {
+ mHandler.removeCallbacks(mCurrentViewHostRunnable);
+ mCurrentViewHostRunnable = null;
+ }
+ }
+
+ /**
+ * Relayout the window decoration but repost some of the work, to unblock the current callstack.
+ */
+ private void relayoutWithDelayedViewHost(ActivityManager.RunningTaskInfo taskInfo,
+ SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
+ boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
+ if (applyStartTransactionOnDraw) {
+ throw new IllegalArgumentException(
+ "We cannot both sync viewhost ondraw and delay viewhost creation.");
+ }
+ // Clear the current ViewHost runnable as we will update the ViewHost here
+ clearCurrentViewHostRunnable();
+ updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT,
+ false /* applyStartTransactionOnDraw */, shouldSetTaskPositionAndCrop);
+ if (mResult.mRootView == null) {
+ // This means something blocks the window decor from showing, e.g. the task is hidden.
+ // Nothing is set up in this case including the decoration surface.
+ return;
+ }
+ // Store the current runnable so it can be removed if we start a new relayout.
+ mCurrentViewHostRunnable = mViewHostRunnable;
+ mHandler.post(mCurrentViewHostRunnable);
+ }
+
+ private void updateRelayoutParamsAndSurfaces(ActivityManager.RunningTaskInfo taskInfo,
+ SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
+ boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
+ Trace.beginSection("DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces");
if (isHandleMenuActive()) {
mHandleMenu.relayout(startT);
}
@@ -216,8 +289,8 @@
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
final WindowContainerTransaction wct = new WindowContainerTransaction();
- Trace.beginSection("DesktopModeWindowDecoration#relayout-inner");
- relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
+ Trace.beginSection("DesktopModeWindowDecoration#relayout-updateViewsAndSurfaces");
+ updateViewsAndSurfaces(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
Trace.endSection();
// After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
@@ -228,7 +301,7 @@
if (mResult.mRootView == null) {
// This means something blocks the window decor from showing, e.g. the task is hidden.
// Nothing is set up in this case including the decoration surface.
- Trace.endSection(); // DesktopModeWindowDecoration#relayout
+ Trace.endSection(); // DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces
return;
}
@@ -246,7 +319,7 @@
updateDragResizeListener(oldDecorationSurface);
updateMaximizeMenu(startT);
- Trace.endSection(); // DesktopModeWindowDecoration#relayout
+ Trace.endSection(); // DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces
}
private void updateDragResizeListener(SurfaceControl oldDecorationSurface) {
@@ -851,6 +924,7 @@
closeHandleMenu();
mExclusionRegionListener.onExclusionRegionDismissed(mTaskInfo.taskId);
disposeResizeVeil();
+ clearCurrentViewHostRunnable();
super.close();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index b9532dd..216990c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -199,8 +199,16 @@
void relayout(RelayoutParams params, SurfaceControl.Transaction startT,
SurfaceControl.Transaction finishT, WindowContainerTransaction wct, T rootView,
RelayoutResult<T> outResult) {
- outResult.reset();
+ updateViewsAndSurfaces(params, startT, finishT, wct, rootView, outResult);
+ if (outResult.mRootView != null) {
+ updateViewHost(params, startT, outResult);
+ }
+ }
+ protected void updateViewsAndSurfaces(RelayoutParams params,
+ SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
+ WindowContainerTransaction wct, T rootView, RelayoutResult<T> outResult) {
+ outResult.reset();
if (params.mRunningTaskInfo != null) {
mTaskInfo = params.mRunningTaskInfo;
}
@@ -236,7 +244,6 @@
updateCaptionContainerSurface(startT, outResult);
updateCaptionInsets(params, wct, outResult, taskBounds);
updateTaskSurface(params, startT, finishT, outResult);
- updateViewHost(params, startT, outResult);
}
private void inflateIfNeeded(RelayoutParams params, WindowContainerTransaction wct,
@@ -410,8 +417,17 @@
}
}
- private void updateViewHost(RelayoutParams params, SurfaceControl.Transaction onDrawTransaction,
- RelayoutResult<T> outResult) {
+ /**
+ * Updates a {@link SurfaceControlViewHost} to connect the window decoration surfaces with our
+ * View hierarchy.
+ *
+ * @param params parameters to use from the last relayout
+ * @param onDrawTransaction a transaction to apply in sync with #onDraw
+ * @param outResult results to use from the last relayout
+ *
+ */
+ protected void updateViewHost(RelayoutParams params,
+ SurfaceControl.Transaction onDrawTransaction, RelayoutResult<T> outResult) {
Trace.beginSection("CaptionViewHostLayout");
if (mCaptionWindowManager == null) {
// Put caption under a container surface because ViewRootImpl sets the destination frame
@@ -433,6 +449,9 @@
mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
mCaptionWindowManager);
if (params.mApplyStartTransactionOnDraw) {
+ if (onDrawTransaction == null) {
+ throw new IllegalArgumentException("Trying to sync a null Transaction");
+ }
mViewHost.getRootSurfaceControl().applyTransactionOnDraw(onDrawTransaction);
}
mViewHost.setView(outResult.mRootView, lp);
@@ -440,6 +459,9 @@
} else {
Trace.beginSection("CaptionViewHostLayout-relayout");
if (params.mApplyStartTransactionOnDraw) {
+ if (onDrawTransaction == null) {
+ throw new IllegalArgumentException("Trying to sync a null Transaction");
+ }
mViewHost.getRootSurfaceControl().applyTransactionOnDraw(onDrawTransaction);
}
mViewHost.relayout(lp);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index f55c96c..93e4051 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -1170,9 +1170,9 @@
// Verify the update has the removals.
BubbleData.Update update = mUpdateCaptor.getValue();
assertThat(update.removedBubbles.get(0)).isEqualTo(
- Pair.create(mBubbleA2, Bubbles.DISMISS_USER_REMOVED));
+ Pair.create(mBubbleA2, Bubbles.DISMISS_USER_ACCOUNT_REMOVED));
assertThat(update.removedBubbles.get(1)).isEqualTo(
- Pair.create(mBubbleA1, Bubbles.DISMISS_USER_REMOVED));
+ Pair.create(mBubbleA1, Bubbles.DISMISS_USER_ACCOUNT_REMOVED));
// Verify no A bubbles in active or overflow.
assertBubbleListContains(mBubbleC1, mBubbleB3);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 1b223cf..46c1589 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -23,12 +23,15 @@
import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -37,7 +40,7 @@
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.res.Configuration;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Handler;
@@ -47,13 +50,19 @@
import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
+import android.view.AttachedSurfaceControl;
import android.view.Choreographer;
import android.view.Display;
+import android.view.GestureDetector;
+import android.view.InsetsState;
+import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
+import android.view.View;
import android.view.WindowManager;
import android.window.WindowContainerTransaction;
+import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
@@ -74,6 +83,7 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.quality.Strictness;
@@ -112,18 +122,25 @@
@Mock
private Supplier<SurfaceControl.Transaction> mMockTransactionSupplier;
@Mock
- private SurfaceControl.Transaction mMockTransaction;
- @Mock
private SurfaceControl mMockSurfaceControl;
@Mock
private SurfaceControlViewHost mMockSurfaceControlViewHost;
@Mock
+ private AttachedSurfaceControl mMockRootSurfaceControl;
+ @Mock
private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory;
@Mock
private TypedArray mMockRoundedCornersRadiusArray;
- private final Configuration mConfiguration = new Configuration();
+ @Mock
+ private TestTouchEventListener mMockTouchEventListener;
+ @Mock
+ private DesktopModeWindowDecoration.ExclusionRegionListener mMockExclusionRegionListener;
+ @Mock
+ private PackageManager mMockPackageManager;
+ private final InsetsState mInsetsState = new InsetsState();
+ private SurfaceControl.Transaction mMockTransaction;
private StaticMockitoSession mMockitoSession;
private TestableContext mTestableContext;
@@ -145,9 +162,17 @@
when(DesktopModeStatus.useDesktopOverrideDensity()).thenReturn(false);
doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory).create(
any(), any(), any());
+ when(mMockSurfaceControlViewHost.getRootSurfaceControl())
+ .thenReturn(mMockRootSurfaceControl);
+ mMockTransaction = createMockSurfaceControlTransaction();
doReturn(mMockTransaction).when(mMockTransactionSupplier).get();
mTestableContext = new TestableContext(mContext);
mTestableContext.ensureTestableResources();
+ mContext.setMockPackageManager(mMockPackageManager);
+ when(mMockPackageManager.getApplicationLabel(any())).thenReturn("applicationLabel");
+ final Display defaultDisplay = mock(Display.class);
+ doReturn(defaultDisplay).when(mMockDisplayController).getDisplay(Display.DEFAULT_DISPLAY);
+ doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt());
}
@After
@@ -341,6 +366,99 @@
assertThat(hasNoInputChannelFeature(relayoutParams)).isTrue();
}
+ @Test
+ public void relayout_fullscreenTask_appliesTransactionImmediately() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ spyWindowDecor.relayout(taskInfo);
+
+ verify(mMockTransaction).apply();
+ verify(mMockRootSurfaceControl, never()).applyTransactionOnDraw(any());
+ }
+
+ @Test
+ public void relayout_freeformTask_appliesTransactionOnDraw() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ // Make non-resizable to avoid dealing with input-permissions (MONITOR_INPUT)
+ taskInfo.isResizeable = false;
+
+ spyWindowDecor.relayout(taskInfo);
+
+ verify(mMockTransaction, never()).apply();
+ verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockTransaction);
+ }
+
+ @Test
+ public void relayout_fullscreenTask_doesNotCreateViewHostImmediately() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ spyWindowDecor.relayout(taskInfo);
+
+ verify(mMockSurfaceControlViewHostFactory, never()).create(any(), any(), any());
+ }
+
+ @Test
+ public void relayout_fullscreenTask_postsViewHostCreation() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
+ spyWindowDecor.relayout(taskInfo);
+
+ verify(mMockHandler).post(runnableArgument.capture());
+ runnableArgument.getValue().run();
+ verify(mMockSurfaceControlViewHostFactory).create(any(), any(), any());
+ }
+
+ @Test
+ public void relayout_freeformTask_createsViewHostImmediately() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ // Make non-resizable to avoid dealing with input-permissions (MONITOR_INPUT)
+ taskInfo.isResizeable = false;
+
+ spyWindowDecor.relayout(taskInfo);
+
+ verify(mMockSurfaceControlViewHostFactory).create(any(), any(), any());
+ verify(mMockHandler, never()).post(any());
+ }
+
+ @Test
+ public void relayout_removesExistingHandlerCallback() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
+ spyWindowDecor.relayout(taskInfo);
+ verify(mMockHandler).post(runnableArgument.capture());
+
+ spyWindowDecor.relayout(taskInfo);
+
+ verify(mMockHandler).removeCallbacks(runnableArgument.getValue());
+ }
+
+ @Test
+ public void close_removesExistingHandlerCallback() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+ final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
+ taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
+ spyWindowDecor.relayout(taskInfo);
+ verify(mMockHandler).post(runnableArgument.capture());
+
+ spyWindowDecor.close();
+
+ verify(mMockHandler).removeCallbacks(runnableArgument.getValue());
+ }
+
private void fillRoundedCornersResources(int fillValue) {
when(mMockRoundedCornersRadiusArray.getDimensionPixelSize(anyInt(), anyInt()))
.thenReturn(fillValue);
@@ -361,12 +479,16 @@
private DesktopModeWindowDecoration createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo) {
- return new DesktopModeWindowDecoration(mContext, mMockDisplayController,
- mMockShellTaskOrganizer, taskInfo, mMockSurfaceControl,
+ DesktopModeWindowDecoration windowDecor = new DesktopModeWindowDecoration(mContext,
+ mMockDisplayController, mMockShellTaskOrganizer, taskInfo, mMockSurfaceControl,
mMockHandler, mMockChoreographer, mMockSyncQueue, mMockRootTaskDisplayAreaOrganizer,
SurfaceControl.Builder::new, mMockTransactionSupplier,
WindowContainerTransaction::new, SurfaceControl::new,
mMockSurfaceControlViewHostFactory);
+ windowDecor.setCaptionListeners(mMockTouchEventListener, mMockTouchEventListener,
+ mMockTouchEventListener, mMockTouchEventListener);
+ windowDecor.setExclusionRegionListener(mMockExclusionRegionListener);
+ return windowDecor;
}
private ActivityManager.RunningTaskInfo createTaskInfo(boolean visible) {
@@ -391,4 +513,32 @@
return (params.mInputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL)
!= 0;
}
+
+ private static class TestTouchEventListener extends GestureDetector.SimpleOnGestureListener
+ implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
+ View.OnGenericMotionListener, DragDetector.MotionEventHandler {
+
+ @Override
+ public void onClick(View v) {}
+
+ @Override
+ public boolean onGenericMotion(View v, MotionEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ return false;
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean handleMotionEvent(@Nullable View v, MotionEvent ev) {
+ return false;
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index e73069a..f3603e1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -32,6 +32,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
@@ -828,6 +829,36 @@
eq(mMockTaskSurface), anyInt(), anyInt());
}
+ @Test
+ public void updateViewHost_applyTransactionOnDrawIsTrue_surfaceControlIsUpdated() {
+ final TestWindowDecoration windowDecor = createWindowDecoration(
+ new TestRunningTaskInfoBuilder().build());
+ mRelayoutParams.mApplyStartTransactionOnDraw = true;
+
+ windowDecor.updateViewHost(mRelayoutParams, mMockSurfaceControlStartT, mRelayoutResult);
+
+ verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT);
+ }
+
+ @Test
+ public void updateViewHost_nullDrawTransaction_applyTransactionOnDrawIsTrue_throwsException() {
+ final TestWindowDecoration windowDecor = createWindowDecoration(
+ new TestRunningTaskInfoBuilder().build());
+ mRelayoutParams.mApplyStartTransactionOnDraw = true;
+
+ assertThrows(IllegalArgumentException.class,
+ () -> windowDecor.updateViewHost(
+ mRelayoutParams, null /* onDrawTransaction */, mRelayoutResult));
+ }
+
+ @Test
+ public void updateViewHost_nullDrawTransaction_applyTransactionOnDrawIsFalse_doesNotThrow() {
+ final TestWindowDecoration windowDecor = createWindowDecoration(
+ new TestRunningTaskInfoBuilder().build());
+ mRelayoutParams.mApplyStartTransactionOnDraw = false;
+
+ windowDecor.updateViewHost(mRelayoutParams, null /* onDrawTransaction */, mRelayoutResult);
+ }
private TestWindowDecoration createWindowDecoration(ActivityManager.RunningTaskInfo taskInfo) {
return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml
index bc8a969..91385c6 100644
--- a/packages/CredentialManager/res/values-pt-rBR/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml
@@ -48,7 +48,7 @@
<string name="passwords" msgid="5419394230391253816">"senhas"</string>
<string name="sign_ins" msgid="4710739369149469208">"logins"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informações de login"</string>
- <string name="save_credential_to_title" msgid="3172811692275634301">"Salvar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> em"</string>
+ <string name="save_credential_to_title" msgid="3172811692275634301">"Salvar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> no"</string>
<string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Criar chave de acesso em outro dispositivo?"</string>
<string name="save_password_on_other_device_title" msgid="5829084591948321207">"Salvar senha em outro dispositivo?"</string>
<string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Salvar credenciais de login em outro dispositivo?"</string>
@@ -57,9 +57,9 @@
<string name="set_as_default" msgid="4415328591568654603">"Definir como padrão"</string>
<string name="settings" msgid="6536394145760913145">"Configurações"</string>
<string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
- <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
- <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas"</string>
- <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> chaves de acesso"</string>
+ <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Senhas (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>) • Chaves de acesso (<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>)"</string>
+ <string name="more_options_usage_passwords" msgid="1632047277723187813">"Senhas (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>)"</string>
+ <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Chaves de acesso (<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>)"</string>
<string name="more_options_usage_credentials" msgid="1785697001787193984">"<xliff:g id="TOTALCREDENTIALSNUMBER">%1$s</xliff:g> credenciais"</string>
<string name="passkey_before_subtitle" msgid="2448119456208647444">"Chave de acesso"</string>
<string name="another_device" msgid="5147276802037801217">"Outro dispositivo"</string>
diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml
index bc8a969..91385c6 100644
--- a/packages/CredentialManager/res/values-pt/strings.xml
+++ b/packages/CredentialManager/res/values-pt/strings.xml
@@ -48,7 +48,7 @@
<string name="passwords" msgid="5419394230391253816">"senhas"</string>
<string name="sign_ins" msgid="4710739369149469208">"logins"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informações de login"</string>
- <string name="save_credential_to_title" msgid="3172811692275634301">"Salvar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> em"</string>
+ <string name="save_credential_to_title" msgid="3172811692275634301">"Salvar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> no"</string>
<string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Criar chave de acesso em outro dispositivo?"</string>
<string name="save_password_on_other_device_title" msgid="5829084591948321207">"Salvar senha em outro dispositivo?"</string>
<string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Salvar credenciais de login em outro dispositivo?"</string>
@@ -57,9 +57,9 @@
<string name="set_as_default" msgid="4415328591568654603">"Definir como padrão"</string>
<string name="settings" msgid="6536394145760913145">"Configurações"</string>
<string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
- <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
- <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas"</string>
- <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> chaves de acesso"</string>
+ <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Senhas (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>) • Chaves de acesso (<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>)"</string>
+ <string name="more_options_usage_passwords" msgid="1632047277723187813">"Senhas (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>)"</string>
+ <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Chaves de acesso (<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>)"</string>
<string name="more_options_usage_credentials" msgid="1785697001787193984">"<xliff:g id="TOTALCREDENTIALSNUMBER">%1$s</xliff:g> credenciais"</string>
<string name="passkey_before_subtitle" msgid="2448119456208647444">"Chave de acesso"</string>
<string name="another_device" msgid="5147276802037801217">"Outro dispositivo"</string>
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 652e62c..5728c8c 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -18,6 +18,7 @@
import android.content.Intent
import android.os.Bundle
+import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
@@ -33,6 +34,7 @@
@OptIn(ExperimentalHorologistApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
+ Log.d(TAG, "onCreate, intent: $intent")
super.onCreate(savedInstanceState)
setTheme(android.R.style.Theme_DeviceDefault)
setContent {
@@ -47,6 +49,7 @@
}
override fun onNewIntent(intent: Intent) {
+ Log.d(TAG, "onNewIntent, intent: $intent")
super.onNewIntent(intent)
setIntent(intent)
viewModel.updateRequest(intent)
diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index 1500583..754abb2 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -33,7 +33,7 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
- android:icon="@drawable/android14_patch_adaptive"
+ android:icon="@drawable/android15_patch_adaptive"
android:label="@string/app_name">
<!-- Android V easter egg: Daydream version of Landroid
@@ -41,7 +41,7 @@
<service
android:name=".landroid.DreamUniverse"
android:exported="true"
- android:icon="@drawable/android14_patch_adaptive"
+ android:icon="@drawable/android15_patch_adaptive"
android:label="@string/v_egg_name"
android:description="@string/dream_description"
android:enabled="false"
@@ -62,7 +62,7 @@
android:name=".landroid.MainActivity"
android:exported="true"
android:label="@string/u_egg_name"
- android:icon="@drawable/android14_patch_adaptive"
+ android:icon="@drawable/android15_patch_adaptive"
android:configChanges="orientation|screenLayout|screenSize|density"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen">
<intent-filter>
diff --git a/packages/EasterEgg/res/drawable/android15_patch_adaptive.xml b/packages/EasterEgg/res/drawable/android15_patch_adaptive.xml
new file mode 100644
index 0000000..d949200
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android15_patch_adaptive.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/android15_patch_adaptive_background"/>
+ <foreground android:drawable="@drawable/android15_patch_adaptive_foreground"/>
+ <monochrome android:drawable="@drawable/android15_patch_monochrome"/>
+</adaptive-icon>
diff --git a/packages/EasterEgg/res/drawable/android15_patch_adaptive_background.xml b/packages/EasterEgg/res/drawable/android15_patch_adaptive_background.xml
new file mode 100644
index 0000000..642b30a
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android15_patch_adaptive_background.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <!-- space -->
+ <path
+ android:pathData="M0,0h108v108h-108z"
+ android:fillColor="#202124"/>
+ <!-- stars -->
+ <group>
+ <path
+ android:pathData="M32,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M33,61 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M71,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M62,56 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M68,47 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M72,55 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,36 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+
+ <path
+ android:pathData="M72,49 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M46,53 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M32,45 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M43,37 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M78,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M34,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M76,41 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,46 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ </group>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/android15_patch_adaptive_foreground.xml b/packages/EasterEgg/res/drawable/android15_patch_adaptive_foreground.xml
new file mode 100644
index 0000000..1100eb7
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android15_patch_adaptive_foreground.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+
+ <!-- zoomies -->
+ <group>
+ <path
+ android:pathData="M53,42C52.21,50.58 46.46,68.95 32.11,74.63C19.22,79.75 5.77,82.32 1.19,83.19C0.68,83.29 0.28,83.36 0,83.42V108H54H108V83.42C107.72,83.36 107.32,83.29 106.81,83.19C102.23,82.32 88.78,79.75 75.89,74.63C61.54,68.95 55.79,50.58 55,42H54H53Z"
+ android:fillColor="#C6FF00"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M53.25,42C52.88,50.53 50.44,69.01 43.68,74.67C36.91,80.33 32.65,82.86 31.37,83.41L54,102.87L76.63,83.41C75.35,82.86 71.09,80.33 64.32,74.67C57.56,69.01 55.12,50.53 54.75,42H54H53.25Z"
+ android:fillColor="#ffffff"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M54,42m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#ffffff"/>
+ </group>
+ <group>
+ <!-- head! it's like sputnik -->
+ <path
+ android:pathData="M54,94.25m-26.25,0a26.25,26.25 0,1 1,52.5 0a26.25,26.25 0,1 1,-52.5 0"
+ android:fillColor="#34A853"/>
+ <!-- ant -->
+ <path
+ android:pathData="M38,63.5L44.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#34A853"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M70,63.5L63.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#34A853"
+ android:strokeLineCap="round"/>
+ </group>
+ <!-- spaceship -->
+ <path
+ android:pathData="M54,34C52.34,34 51,35.29 51,36.88V40.44C51,40.75 51.25,41 51.56,41C51.87,41 52.13,40.75 52.13,40.44V39.48C52.13,38.87 52.63,38.37 53.25,38.37H54.75C55.37,38.37 55.87,38.87 55.87,39.48V40.44C55.87,40.75 56.13,41 56.44,41C56.75,41 57,40.75 57,40.44V36.88C57,35.29 55.66,34 54,34H54Z"
+ android:fillColor="#E9F3EB"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/android15_patch_monochrome.xml b/packages/EasterEgg/res/drawable/android15_patch_monochrome.xml
new file mode 100644
index 0000000..a91cc86
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android15_patch_monochrome.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <group>
+ <path
+ android:pathData="
+ M54,94.25
+ m-26.25,0
+ a26.25,26.25 0,1 1,52.5 0
+ a26.25,26.25 0,1 1,-52.5 0
+ "
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M38,63.5L44.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M70,63.5L63.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeLineCap="round"/>
+
+ <path
+ android:pathData="
+ M54,34
+ C52.34,34 51,35.29 51,36.88
+ V40.44
+ C51,40.75 51.25,41 51.56,41
+ C51.87,41 52.13,40.75 52.13,40.44
+ V39.48
+ C52.13,38.87 52.63,38.37 53.25,38.37
+ H54.75
+ C55.37,38.37 55.87,38.87 55.87,39.48
+ V40.44
+ C55.87,40.75 56.13,41 56.44,41
+ C56.75,41 57,40.75 57,40.44
+ V36.88
+ C57,35.29 55.66,34 54,34
+ H54
+ Z
+ "
+ android:fillColor="#34A853"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M54,40V67"
+ android:fillColor="#00000000"
+ android:strokeColor="#40FFFFFF"
+ />
+
+ <path
+ android:pathData="M32,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M33,61 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M71,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M62,56 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M68,47 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M72,55 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,36 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+
+ <path
+ android:pathData="M72,49 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M46,53 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M32,45 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M43,37 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M78,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M34,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M76,41 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,46 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+
+ </group>
+</vector>
diff --git a/packages/PackageInstaller/res/values-pa/strings.xml b/packages/PackageInstaller/res/values-pa/strings.xml
index 1db92a0..80dc889 100644
--- a/packages/PackageInstaller/res/values-pa/strings.xml
+++ b/packages/PackageInstaller/res/values-pa/strings.xml
@@ -63,7 +63,7 @@
<string name="archive_application_text_all_users" msgid="3151229641681672580">"ਕੀ ਇਸ ਐਪ ਨੂੰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਲਈ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਹੈ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
<string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"ਕੀ ਇਸ ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਹੈ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
<string name="archive_application_text_user" msgid="2586558895535581451">"ਕੀ ਇਸ ਐਪ ਨੂੰ <xliff:g id="USERNAME">%1$s</xliff:g> ਲਈ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਹੈ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
- <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਆਪਣੀ ਨਿੱਜੀ ਸਪੇਸ ਤੋਂ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
+ <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਆਪਣੀ ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਤੋਂ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ "<b>"ਸਾਰੇ"</b>" ਵਰਤੋਂਕਾਰਾਂ ਲਈ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? ਐਪਲੀਕੇਸ਼ਨ ਅਤੇ ਇਸਦਾ ਡਾਟਾ ਡੀਵਾਈਸ \'ਤੇ "<b>"ਸਾਰੇ"</b>" ਵਰਤੋਂਕਾਰਾਂ ਵੱਲੋਂ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"ਕੀ ਤੁਸੀਂ ਵਰਤੋਂਕਾਰ <xliff:g id="USERNAME">%1$s</xliff:g> ਲਈ ਇਸ ਐਪ ਨੂੰ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਆਪਣੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਤੋਂ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
diff --git a/packages/PackageInstaller/res/values-tr/strings.xml b/packages/PackageInstaller/res/values-tr/strings.xml
index 006ad52..e10eb0e 100644
--- a/packages/PackageInstaller/res/values-tr/strings.xml
+++ b/packages/PackageInstaller/res/values-tr/strings.xml
@@ -55,7 +55,7 @@
<string name="user_is_not_allowed_dlg_text" msgid="3468447791330611681">"Geçerli kullanıcının bu yüklemeyi kaldırma izni yok."</string>
<string name="generic_error_dlg_title" msgid="5863195085927067752">"Hata"</string>
<string name="generic_error_dlg_text" msgid="5287861443265795232">"Uygulamanın yüklemesi kaldırılamadı."</string>
- <string name="uninstall_application_title" msgid="4045420072401428123">"Uygulamanın yüklemesini kaldır"</string>
+ <string name="uninstall_application_title" msgid="4045420072401428123">"Uygulamayı kaldır"</string>
<string name="uninstall_update_title" msgid="824411791011583031">"Güncelleme kaldırılsın mı?"</string>
<string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g>, şu uygulamanın bir parçasıdır:"</string>
<string name="uninstall_application_text" msgid="3816830743706143980">"Bu uygulamanın yüklemesini kaldırmak istiyor musunuz?"</string>
diff --git a/packages/PrintSpooler/res/values-as/strings.xml b/packages/PrintSpooler/res/values-as/strings.xml
index 020eac7..950c5c8 100644
--- a/packages/PrintSpooler/res/values-as/strings.xml
+++ b/packages/PrintSpooler/res/values-as/strings.xml
@@ -100,7 +100,7 @@
</string-array>
<string-array name="orientation_labels">
<item msgid="4061931020926489228">"প\'ৰ্ট্ৰেইট"</item>
- <item msgid="3199660090246166812">"লেণ্ডস্কেইপ"</item>
+ <item msgid="3199660090246166812">"লেণ্ডস্কে’প"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"ফাইলত লিখিব পৰা নহ\'ল"</string>
<string name="print_error_default_message" msgid="8602678405502922346">"দুঃখিত, প্ৰিণ্টিঙৰ কাম নহ\'ল। পুনৰ চেষ্টা কৰক।"</string>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml
index eb33d57..75e1a18 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml
@@ -19,5 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Pessoal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Trabalho"</string>
- <string name="settingslib_category_private" msgid="5039276873477591386">"Particular"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Privado"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml
index eb33d57..75e1a18 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml
@@ -19,5 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Pessoal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Trabalho"</string>
- <string name="settingslib_category_private" msgid="5039276873477591386">"Particular"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Privado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index f0fb4df..caeee06 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -710,7 +710,7 @@
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
<string name="turn_screen_on_title" msgid="2662312432042116026">"Steuerelement zum Aktivieren des Displays"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Aktivieren des Displays erlauben"</string>
- <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Einer App erlauben, das Display zu aktivieren. Wenn du diese Erlaubnis erteilst, kann die App jederzeit das Display aktivieren – auch ohne deine explizite Absicht."</string>
+ <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Einer App erlauben, das Display zu aktivieren. Wenn du diese Erlaubnis erteilst, kann die App jederzeit das Display aktivieren – auch ohne dass du dies beabsichtigst."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> nicht mehr streamen?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Wenn du <xliff:g id="SWITCHAPP">%1$s</xliff:g> streamst oder die Ausgabe änderst, wird dein aktueller Stream beendet"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> streamen"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 1381903..a25e179 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -632,7 +632,7 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ಪ್ರೊಫೈಲ್ ಮಾಹಿತಿ"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"ನೀವು ನಿರ್ಬಂಧಿತ ಪ್ರೊಫೈಲ್ ಅನ್ನು ರಚಿಸಬಹುದಾದರ ಮೊದಲು, ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ರಕ್ಷಿಸಲು ನೀವು ಪರದೆಯ ಲಾಕ್ ಹೊಂದಿಸುವ ಅಗತ್ಯವಿದೆ."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ಲಾಕ್ ಹೊಂದಿಸಿ"</string>
- <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> ಗೆ ಬದಲಿಸಿ"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>ಗೆ ಬದಲಿಸಿ"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ಹೊಸ ಅತಿಥಿಯನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 5032e35..1e33f88 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -641,7 +641,7 @@
<string name="edit_user_info_message" msgid="6677556031419002895">"यो डिभाइस प्रयोग गर्ने सबै जना तपाईंले छनौट गर्ने नाम र फोटो देख्न सक्ने छन्।"</string>
<string name="user_add_user" msgid="7876449291500212468">"प्रयोगकर्ता कनेक्ट गर्नुहोस्"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथि कनेक्ट गर्नुहोस्"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"गेस्ट मोडबाट बाहिर निस्कियोस्"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"अथिति हटाउनुहोस्"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"अतिथि सत्र रिसेट गर्नुहोस्"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"अतिथिका रूपमा ब्राउज गर्ने सेसन रिसेट गर्ने हो?"</string>
<string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"यी अतिथि हटाउने हो?"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index d47a1f4..337b011 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -237,7 +237,7 @@
<string name="choose_profile" msgid="343803890897657450">"Escolher perfil"</string>
<string name="category_personal" msgid="6236798763159385225">"Pessoal"</string>
<string name="category_work" msgid="4014193632325996115">"Trabalho"</string>
- <string name="category_private" msgid="4244892185452788977">"Particular"</string>
+ <string name="category_private" msgid="4244892185452788977">"Privado"</string>
<string name="category_clone" msgid="1554511758987195974">"Clone"</string>
<string name="development_settings_title" msgid="140296922921597393">"Opções do desenvolvedor"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Ativar opções do desenvolvedor"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index d47a1f4..337b011 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -237,7 +237,7 @@
<string name="choose_profile" msgid="343803890897657450">"Escolher perfil"</string>
<string name="category_personal" msgid="6236798763159385225">"Pessoal"</string>
<string name="category_work" msgid="4014193632325996115">"Trabalho"</string>
- <string name="category_private" msgid="4244892185452788977">"Particular"</string>
+ <string name="category_private" msgid="4244892185452788977">"Privado"</string>
<string name="category_clone" msgid="1554511758987195974">"Clone"</string>
<string name="development_settings_title" msgid="140296922921597393">"Opções do desenvolvedor"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Ativar opções do desenvolvedor"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index ff62ba0..e8acd6e 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -161,7 +161,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"ரத்துசெய்"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"இணைத்தலானது உங்கள் தொடர்புகள், அழைப்பு வரலாறுக்கான அணுகலை வழங்குகிறது."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் இணைய முடியவில்லை."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"தவறான பின் அல்லது கடவுச்சொல் காரணமாக <xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் இணைக்க முடியவில்லை."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"தவறான பின் அல்லது கடவுச்சாவி காரணமாக <xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் இணைக்க முடியவில்லை."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் இணைக்க முடியவில்லை."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> இணைப்பதை நிராகரித்தது."</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"கணினி"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 6aea659..e8bac31 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -492,9 +492,9 @@
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tamamen şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
<string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj işlemi optimize edildi"</string>
<string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ Şarj ediliyor"</string>
- <string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - <xliff:g id="TIME">%3$s</xliff:g> içinde tamamen dolacak"</string>
- <string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> içinde tamamen şarj olacak"</string>
- <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"<xliff:g id="TIME">%1$s</xliff:g> içinde tamamen şarj olacak"</string>
+ <string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - Tamamen dolacağı zaman: <xliff:g id="TIME">%3$s</xliff:g>"</string>
+ <string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tamamen şarj olacağı zaman: <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Tamamen şarj olacağı zaman: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"<xliff:g id="TIME">%1$s</xliff:g> itibarıyla tamamen dolacak"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Bilinmiyor"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Şarj oluyor"</string>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index bd6efe5..8a99263 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -387,7 +387,7 @@
android:killAfterRestore="false"
android:hardwareAccelerated="true"
android:label="@string/app_label"
- android:icon="@drawable/android14_patch_adaptive"
+ android:icon="@drawable/android15_patch_adaptive"
android:process="com.android.systemui"
android:supportsRtl="true"
android:theme="@style/Theme.SystemUI"
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml
index 160d310..f12278a 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml
@@ -2,7 +2,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="accessibility_menu_service_name" msgid="730136711554740131">"Menu de acessibilidade"</string>
- <string name="accessibility_menu_intro" msgid="3164193281544042394">"\"Acessibilidade\" é um menu grande mostrado na tela para controlar seu dispositivo. Você pode bloquear o dispositivo, controlar o volume e o brilho, fazer capturas de tela e muito mais."</string>
+ <string name="accessibility_menu_intro" msgid="3164193281544042394">"Com este menu de tamanho grande na tela, você consegue bloquear o dispositivo, ajustar o volume e o brilho, fazer capturas de tela, entre outras funções de controle do aparelho."</string>
<string name="assistant_label" msgid="6796392082252272356">"Assistente"</string>
<string name="assistant_utterance" msgid="65509599221141377">"Google Assistente"</string>
<string name="a11y_settings_label" msgid="3977714687248445050">"Configurações de acessibilidade"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml
index 160d310..f12278a 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml
@@ -2,7 +2,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="accessibility_menu_service_name" msgid="730136711554740131">"Menu de acessibilidade"</string>
- <string name="accessibility_menu_intro" msgid="3164193281544042394">"\"Acessibilidade\" é um menu grande mostrado na tela para controlar seu dispositivo. Você pode bloquear o dispositivo, controlar o volume e o brilho, fazer capturas de tela e muito mais."</string>
+ <string name="accessibility_menu_intro" msgid="3164193281544042394">"Com este menu de tamanho grande na tela, você consegue bloquear o dispositivo, ajustar o volume e o brilho, fazer capturas de tela, entre outras funções de controle do aparelho."</string>
<string name="assistant_label" msgid="6796392082252272356">"Assistente"</string>
<string name="assistant_utterance" msgid="65509599221141377">"Google Assistente"</string>
<string name="a11y_settings_label" msgid="3977714687248445050">"Configurações de acessibilidade"</string>
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index b1258ba..c4659cf 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -55,6 +55,7 @@
import com.android.systemui.communal.shared.model.CommunalBackgroundType
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
+import com.android.systemui.communal.ui.compose.Dimensions.SlideOffsetY
import com.android.systemui.communal.ui.compose.extensions.allowGestures
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.util.CommunalColors
@@ -76,6 +77,15 @@
override fun matches(key: ElementKey, scene: SceneKey) = true
}
+private object TransitionDuration {
+ const val BETWEEN_HUB_AND_EDIT_MODE_MS = 1000
+ const val EDIT_MODE_TO_HUB_CONTENT_MS = 167
+ const val EDIT_MODE_TO_HUB_GRID_DELAY_MS = 167
+ const val EDIT_MODE_TO_HUB_GRID_END_MS =
+ EDIT_MODE_TO_HUB_GRID_DELAY_MS + EDIT_MODE_TO_HUB_CONTENT_MS
+ const val HUB_TO_EDIT_MODE_CONTENT_MS = 250
+}
+
val sceneTransitions = transitions {
to(CommunalScenes.Communal, key = CommunalTransitionKeys.SimpleFade) {
spec = tween(durationMillis = 250)
@@ -97,6 +107,30 @@
}
timestampRange(startMillis = 167, endMillis = 334) { fade(Communal.Elements.Scrim) }
}
+ to(CommunalScenes.Blank, key = CommunalTransitionKeys.ToEditMode) {
+ spec = tween(durationMillis = TransitionDuration.BETWEEN_HUB_AND_EDIT_MODE_MS)
+ timestampRange(endMillis = TransitionDuration.HUB_TO_EDIT_MODE_CONTENT_MS) {
+ fade(Communal.Elements.Grid)
+ fade(Communal.Elements.IndicationArea)
+ fade(Communal.Elements.LockIcon)
+ }
+ fade(Communal.Elements.Scrim)
+ }
+ to(CommunalScenes.Communal, key = CommunalTransitionKeys.FromEditMode) {
+ spec = tween(durationMillis = TransitionDuration.BETWEEN_HUB_AND_EDIT_MODE_MS)
+ translate(Communal.Elements.Grid, y = SlideOffsetY)
+ timestampRange(endMillis = TransitionDuration.EDIT_MODE_TO_HUB_CONTENT_MS) {
+ fade(Communal.Elements.IndicationArea)
+ fade(Communal.Elements.LockIcon)
+ fade(Communal.Elements.Scrim)
+ }
+ timestampRange(
+ startMillis = TransitionDuration.EDIT_MODE_TO_HUB_GRID_DELAY_MS,
+ endMillis = TransitionDuration.EDIT_MODE_TO_HUB_GRID_END_MS
+ ) {
+ fade(Communal.Elements.Grid)
+ }
+ }
}
/**
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 eccb072..a1899fd 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
@@ -26,7 +26,6 @@
import androidx.annotation.VisibleForTesting
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedVisibilityScope
-import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateFloatAsState
@@ -34,6 +33,8 @@
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
+import androidx.compose.animation.slideInVertically
+import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
@@ -46,6 +47,7 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -128,6 +130,7 @@
import androidx.compose.ui.window.Popup
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.layout.WindowMetricsCalculator
+import com.android.compose.animation.Easings.Emphasized
import com.android.compose.modifiers.thenIf
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
@@ -176,6 +179,10 @@
derivedStateOf { selectedKey.value != null || reorderingWidgets }
}
val isEmptyState by viewModel.isEmptyState.collectAsStateWithLifecycle(initialValue = false)
+ val isCommunalContentVisible by
+ viewModel.isCommunalContentVisible.collectAsStateWithLifecycle(
+ initialValue = !viewModel.isEditMode
+ )
val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize)
val contentOffset = beforeContentPadding(contentPadding).toOffset()
@@ -248,47 +255,88 @@
viewModel = viewModel,
)
} else {
- CommunalHubLazyGrid(
- communalContent = communalContent,
- viewModel = viewModel,
- contentPadding = contentPadding,
- contentOffset = contentOffset,
- setGridCoordinates = { gridCoordinates = it },
- updateDragPositionForRemove = { offset ->
- isPointerWithinEnabledRemoveButton(
- removeEnabled = removeButtonEnabled,
- offset = gridCoordinates?.let { it.positionInWindow() + offset },
- containerToCheck = removeButtonCoordinates
+ val slideOffsetInPx =
+ with(LocalDensity.current) { Dimensions.SlideOffsetY.toPx().toInt() }
+ AnimatedVisibility(
+ visible = isCommunalContentVisible,
+ enter =
+ fadeIn(
+ animationSpec =
+ tween(durationMillis = 83, delayMillis = 83, easing = LinearEasing)
+ ) +
+ slideInVertically(
+ animationSpec = tween(durationMillis = 1000, easing = Emphasized),
+ initialOffsetY = { -slideOffsetInPx }
+ ),
+ exit =
+ fadeOut(
+ animationSpec = tween(durationMillis = 167, easing = LinearEasing)
+ ) +
+ slideOutVertically(
+ animationSpec = tween(durationMillis = 1000, easing = Emphasized),
+ targetOffsetY = { -slideOffsetInPx }
+ ),
+ modifier = Modifier.fillMaxSize(),
+ ) {
+ Box {
+ CommunalHubLazyGrid(
+ communalContent = communalContent,
+ viewModel = viewModel,
+ contentPadding = contentPadding,
+ contentOffset = contentOffset,
+ setGridCoordinates = { gridCoordinates = it },
+ updateDragPositionForRemove = { offset ->
+ isPointerWithinEnabledRemoveButton(
+ removeEnabled = removeButtonEnabled,
+ offset =
+ gridCoordinates?.let { it.positionInWindow() + offset },
+ containerToCheck = removeButtonCoordinates
+ )
+ },
+ gridState = gridState,
+ contentListState = contentListState,
+ selectedKey = selectedKey,
+ widgetConfigurator = widgetConfigurator,
+ interactionHandler = interactionHandler,
)
- },
- gridState = gridState,
- contentListState = contentListState,
- selectedKey = selectedKey,
- widgetConfigurator = widgetConfigurator,
- interactionHandler = interactionHandler,
- )
+ }
+ }
}
}
- if (viewModel.isEditMode && onOpenWidgetPicker != null && onEditDone != null) {
- Toolbar(
- setToolbarSize = { toolbarSize = it },
- setRemoveButtonCoordinates = { removeButtonCoordinates = it },
- onEditDone = onEditDone,
- onOpenWidgetPicker = onOpenWidgetPicker,
- onRemoveClicked = {
- val index =
- selectedKey.value?.let { key ->
- contentListState.list.indexOfFirst { it.key == key }
+ if (onOpenWidgetPicker != null && onEditDone != null) {
+ AnimatedVisibility(
+ visible = viewModel.isEditMode && isCommunalContentVisible,
+ enter =
+ fadeIn(animationSpec = tween(durationMillis = 250, easing = LinearEasing)) +
+ slideInVertically(
+ animationSpec = tween(durationMillis = 1000, easing = Emphasized),
+ ),
+ exit =
+ fadeOut(animationSpec = tween(durationMillis = 167, easing = LinearEasing)) +
+ slideOutVertically(
+ animationSpec = tween(durationMillis = 1000, easing = Emphasized)
+ ),
+ ) {
+ Toolbar(
+ setToolbarSize = { toolbarSize = it },
+ setRemoveButtonCoordinates = { removeButtonCoordinates = it },
+ onEditDone = onEditDone,
+ onOpenWidgetPicker = onOpenWidgetPicker,
+ onRemoveClicked = {
+ val index =
+ selectedKey.value?.let { key ->
+ contentListState.list.indexOfFirst { it.key == key }
+ }
+ index?.let {
+ contentListState.onRemove(it)
+ contentListState.onSaveList()
+ viewModel.setSelectedKey(null)
}
- index?.let {
- contentListState.onRemove(it)
- contentListState.onSaveList()
- viewModel.setSelectedKey(null)
- }
- },
- removeEnabled = removeButtonEnabled
- )
+ },
+ removeEnabled = removeButtonEnabled
+ )
+ }
}
if (currentPopup == PopupType.CtaTile) {
PopupOnDismissCtaTile(viewModel::onHidePopup)
@@ -585,24 +633,23 @@
)
.onSizeChanged { setToolbarSize(it) },
) {
- val spacerModifier = Modifier.width(ButtonDefaults.IconSpacing)
-
- if (!removeEnabled) {
- Button(
- modifier = Modifier.align(Alignment.CenterStart),
- onClick = onOpenWidgetPicker,
- colors = filledButtonColors(),
- contentPadding = Dimensions.ButtonPadding
- ) {
- Icon(Icons.Default.Add, stringResource(R.string.hub_mode_add_widget_button_text))
- Spacer(spacerModifier)
- Text(
- text = stringResource(R.string.hub_mode_add_widget_button_text),
- )
- }
+ ToolbarButton(
+ isPrimary = !removeEnabled,
+ modifier = Modifier.align(Alignment.CenterStart),
+ onClick = onOpenWidgetPicker,
+ ) {
+ Icon(Icons.Default.Add, stringResource(R.string.hub_mode_add_widget_button_text))
+ Text(
+ text = stringResource(R.string.hub_mode_add_widget_button_text),
+ )
}
- if (removeEnabled) {
+ AnimatedVisibility(
+ modifier = Modifier.align(Alignment.Center),
+ visible = removeEnabled,
+ enter = fadeIn(),
+ exit = fadeOut()
+ ) {
Button(
onClick = onRemoveClicked,
colors = filledButtonColors(),
@@ -610,33 +657,97 @@
modifier =
Modifier.graphicsLayer { alpha = removeButtonAlpha }
.onGloballyPositioned { setRemoveButtonCoordinates(it) }
- .align(Alignment.Center)
) {
- RemoveButtonContent(spacerModifier)
+ Row(
+ horizontalArrangement =
+ Arrangement.spacedBy(
+ ButtonDefaults.IconSpacing,
+ Alignment.CenterHorizontally
+ ),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(Icons.Default.Close, stringResource(R.string.button_to_remove_widget))
+ Text(
+ text = stringResource(R.string.button_to_remove_widget),
+ )
+ }
}
}
- if (!removeEnabled) {
- Button(
- modifier = Modifier.align(Alignment.CenterEnd),
- onClick = onEditDone,
- colors = filledButtonColors(),
- contentPadding = Dimensions.ButtonPadding
+ ToolbarButton(
+ isPrimary = !removeEnabled,
+ modifier = Modifier.align(Alignment.CenterEnd),
+ onClick = onEditDone,
+ ) {
+ Icon(
+ Icons.Default.Check,
+ stringResource(id = R.string.hub_mode_editing_exit_button_text)
+ )
+ Text(
+ text = stringResource(R.string.hub_mode_editing_exit_button_text),
+ )
+ }
+ }
+}
+
+/**
+ * Toolbar button that displays as a filled button if primary, and an outline button if secondary.
+ */
+@Composable
+private fun ToolbarButton(
+ isPrimary: Boolean = true,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ content: @Composable RowScope.() -> Unit
+) {
+ val colors = LocalAndroidColorScheme.current
+ AnimatedVisibility(
+ visible = isPrimary,
+ modifier = modifier,
+ enter = fadeIn(),
+ exit = fadeOut()
+ ) {
+ Button(
+ onClick = onClick,
+ colors = filledButtonColors(),
+ contentPadding = Dimensions.ButtonPadding,
+ ) {
+ Row(
+ horizontalArrangement =
+ Arrangement.spacedBy(ButtonDefaults.IconSpacing, Alignment.CenterHorizontally),
+ verticalAlignment = Alignment.CenterVertically
) {
- Icon(
- Icons.Default.Check,
- stringResource(id = R.string.hub_mode_editing_exit_button_text)
- )
- Spacer(spacerModifier)
- Text(
- text = stringResource(R.string.hub_mode_editing_exit_button_text),
- )
+ content()
+ }
+ }
+ }
+
+ AnimatedVisibility(
+ visible = !isPrimary,
+ modifier = modifier,
+ enter = fadeIn(),
+ exit = fadeOut()
+ ) {
+ OutlinedButton(
+ onClick = onClick,
+ colors =
+ ButtonDefaults.outlinedButtonColors(
+ contentColor = colors.primary,
+ ),
+ border = BorderStroke(width = 2.0.dp, color = colors.primary),
+ contentPadding = Dimensions.ButtonPadding,
+ ) {
+ Row(
+ horizontalArrangement =
+ Arrangement.spacedBy(ButtonDefaults.IconSpacing, Alignment.CenterHorizontally),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ content()
}
}
}
}
-@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun AnimatedVisibilityScope.ButtonToEditWidgets(
onClick: () -> Unit,
@@ -739,15 +850,6 @@
}
@Composable
-private fun RemoveButtonContent(spacerModifier: Modifier) {
- Icon(Icons.Default.Close, stringResource(R.string.button_to_remove_widget))
- Spacer(spacerModifier)
- Text(
- text = stringResource(R.string.button_to_remove_widget),
- )
-}
-
-@Composable
private fun filledButtonColors(): ButtonColors {
val colors = LocalAndroidColorScheme.current
return ButtonDefaults.buttonColors(
@@ -1277,6 +1379,7 @@
horizontal = ToolbarButtonPaddingHorizontal,
)
val IconSize = 40.dp
+ val SlideOffsetY = 30.dp
}
private object Colors {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
index e1ae80f..6d03118 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
@@ -88,7 +88,7 @@
} else {
MaterialTheme.colorScheme.surface
},
- shape = RoundedCornerShape(28.dp),
+ shape = RoundedCornerShape(20.dp),
contentColor =
if (viewModel.isActive) {
MaterialTheme.colorScheme.onTertiaryContainer
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
index 1b821d3..bb2daec 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
@@ -91,7 +91,7 @@
contentDescription = label
},
onClick = { onCheckedChange(!viewModel.isActive) },
- shape = RoundedCornerShape(28.dp),
+ shape = RoundedCornerShape(20.dp),
colors = colors,
contentPadding = PaddingValues(0.dp)
) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index e61b2d0..cf14547 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -111,6 +111,25 @@
}
}
+ @Test
+ fun keyguardGoesAway_whenInEditMode_doesNotChangeScene() =
+ with(kosmos) {
+ testScope.runTest {
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ communalInteractor.setEditModeOpen(true)
+ fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.ALTERNATE_BOUNCER,
+ to = KeyguardState.GONE,
+ testScope = this
+ )
+ // Scene change will be handled in EditWidgetsActivity not here
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+ }
+ }
+
@Ignore("Ignored until custom animations are implemented in b/322787129")
@Test
fun deviceDocked_forceCommunalScene() =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index e42a67b..3d454a2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -52,6 +52,7 @@
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
+import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
@@ -121,6 +122,7 @@
private lateinit var communalPrefsRepository: FakeCommunalPrefsRepository
private lateinit var editWidgetsActivityStarter: EditWidgetsActivityStarter
private lateinit var sceneInteractor: SceneInteractor
+ private lateinit var communalSceneInteractor: CommunalSceneInteractor
private lateinit var userTracker: FakeUserTracker
private lateinit var activityStarter: ActivityStarter
private lateinit var userManager: UserManager
@@ -141,6 +143,7 @@
editWidgetsActivityStarter = kosmos.editWidgetsActivityStarter
communalPrefsRepository = kosmos.fakeCommunalPrefsRepository
sceneInteractor = kosmos.sceneInteractor
+ communalSceneInteractor = kosmos.communalSceneInteractor
userTracker = kosmos.fakeUserTracker
activityStarter = kosmos.activityStarter
userManager = kosmos.userManager
@@ -815,7 +818,11 @@
@Test
fun testShowWidgetEditorStartsActivity() =
testScope.runTest {
+ val editModeState by collectLastValue(communalSceneInteractor.editModeState)
+
underTest.showWidgetEditor()
+
+ assertThat(editModeState).isEqualTo(EditModeState.STARTING)
verify(editWidgetsActivityStarter).startActivity()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
index a0e7781..6e48b99 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractorTest.kt
@@ -24,6 +24,7 @@
import com.android.systemui.communal.data.repository.communalSceneRepository
import com.android.systemui.communal.domain.model.CommunalTransitionProgressModel
import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
@@ -82,6 +83,27 @@
}
@Test
+ fun snapToSceneForActivity() =
+ testScope.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+ assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
+
+ underTest.snapToSceneForActivityStart(CommunalScenes.Communal)
+ assertThat(currentScene).isEqualTo(CommunalScenes.Communal)
+ }
+
+ @Test
+ fun snapToSceneForActivity_willNotChangeScene_forEditModeActivity() =
+ testScope.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+ assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
+
+ underTest.setEditModeState(EditModeState.STARTING)
+ underTest.snapToSceneForActivityStart(CommunalScenes.Communal)
+ assertThat(currentScene).isEqualTo(CommunalScenes.Blank)
+ }
+
+ @Test
fun transitionProgress_fullProgress() =
testScope.runTest {
val transitionProgress by
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index 84dbfd4..d5fe2a1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -38,14 +38,17 @@
import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.fakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
+import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
@@ -86,6 +89,7 @@
private lateinit var widgetRepository: FakeCommunalWidgetRepository
private lateinit var smartspaceRepository: FakeSmartspaceRepository
private lateinit var mediaRepository: FakeCommunalMediaRepository
+ private lateinit var communalSceneInteractor: CommunalSceneInteractor
private val testableResources = context.orCreateTestableResources
@@ -99,6 +103,7 @@
widgetRepository = kosmos.fakeCommunalWidgetRepository
smartspaceRepository = kosmos.fakeSmartspaceRepository
mediaRepository = kosmos.fakeCommunalMediaRepository
+ communalSceneInteractor = kosmos.communalSceneInteractor
kosmos.fakeUserTracker.set(
userInfos = listOf(MAIN_USER_INFO),
selectedUserIndex = 0,
@@ -107,9 +112,10 @@
underTest =
CommunalEditModeViewModel(
- kosmos.communalSceneInteractor,
+ communalSceneInteractor,
kosmos.communalInteractor,
kosmos.communalSettingsInteractor,
+ kosmos.keyguardTransitionInteractor,
mediaHost,
uiEventLogger,
logcatLogBuffer("CommunalEditModeViewModelTest"),
@@ -172,6 +178,22 @@
}
@Test
+ fun isCommunalContentVisible_isTrue_whenEditModeShowing() =
+ testScope.runTest {
+ val isCommunalContentVisible by collectLastValue(underTest.isCommunalContentVisible)
+ communalSceneInteractor.setEditModeState(EditModeState.SHOWING)
+ assertThat(isCommunalContentVisible).isEqualTo(true)
+ }
+
+ @Test
+ fun isCommunalContentVisible_isFalse_whenEditModeNotShowing() =
+ testScope.runTest {
+ val isCommunalContentVisible by collectLastValue(underTest.isCommunalContentVisible)
+ communalSceneInteractor.setEditModeState(null)
+ assertThat(isCommunalContentVisible).isEqualTo(false)
+ }
+
+ @Test
fun deleteWidget() =
testScope.runTest {
tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
index a12b6f8..d20fec4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
@@ -39,6 +39,7 @@
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -166,4 +167,37 @@
to = KeyguardState.OCCLUDED
)
}
+
+ @Test
+ fun transitionToGone_whenOpeningGlanceableHubEditMode() =
+ testScope.runTest {
+ kosmos.fakeKeyguardBouncerRepository.setAlternateVisible(true)
+ runCurrent()
+
+ // On Glanceable hub and edit mode activity is started
+ transitionRepository.sendTransitionSteps(
+ from = KeyguardState.GLANCEABLE_HUB,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ testScope
+ )
+ reset(transitionRepository)
+
+ kosmos.communalInteractor.setEditModeOpen(true)
+ runCurrent()
+
+ // Auth and alternate bouncer is hidden
+ kosmos.fakeKeyguardBouncerRepository.setAlternateVisible(false)
+ advanceTimeBy(200) // advance past delay
+
+ // Then no transition should occur yet
+ assertThat(transitionRepository).noTransitionsStarted()
+
+ // When keyguard is going away
+ kosmos.fakeKeyguardRepository.setKeyguardGoingAway(true)
+ runCurrent()
+
+ // Then transition to GONE should occur
+ assertThat(transitionRepository)
+ .startedTransition(from = KeyguardState.ALTERNATE_BOUNCER, to = KeyguardState.GONE)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index 9dc930b..6e16705 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -197,7 +197,7 @@
@Test
@EnableSceneContainer
- fun surfaceBehindVisibility_fromLockscreenToGone_trueThroughout() =
+ fun surfaceBehindVisibility_fromLockscreenToGone_noUserInput_trueThroughout() =
testScope.runTest {
val isSurfaceBehindVisible by collectLastValue(underTest.value.surfaceBehindVisibility)
val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
@@ -249,6 +249,43 @@
@Test
@EnableSceneContainer
+ fun surfaceBehindVisibility_fromLockscreenToGone_withUserInput_falseUntilInputStops() =
+ testScope.runTest {
+ val isSurfaceBehindVisible by collectLastValue(underTest.value.surfaceBehindVisibility)
+ val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
+
+ // Before the transition, we start on Lockscreen so the surface should start invisible.
+ kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Lockscreen))
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(isSurfaceBehindVisible).isFalse()
+
+ // Unlocked with fingerprint.
+ kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+
+ // Start the transition to Gone, the surface should not be visible while
+ // isUserInputOngoing is true
+ val isUserInputOngoing = MutableStateFlow(true)
+ kosmos.setSceneTransition(
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Lockscreen,
+ toScene = Scenes.Gone,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = isUserInputOngoing,
+ progress = flowOf(0.51f),
+ currentScene = flowOf(Scenes.Gone),
+ )
+ )
+ assertThat(isSurfaceBehindVisible).isFalse()
+
+ // When isUserInputOngoing becomes false, then the surface should become visible.
+ isUserInputOngoing.value = false
+ assertThat(isSurfaceBehindVisible).isTrue()
+ }
+
+ @Test
+ @EnableSceneContainer
fun surfaceBehindVisibility_fromBouncerToGone_becomesTrue() =
testScope.runTest {
val isSurfaceBehindVisible by collectLastValue(underTest.value.surfaceBehindVisibility)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
index e87c8ad..899122d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
@@ -35,6 +35,7 @@
import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
import com.android.systemui.screenrecord.RecordingController
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
+import com.android.systemui.screenrecord.data.repository.ScreenRecordRepositoryImpl
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
@@ -72,11 +73,18 @@
.thenReturn(dialog)
}
+ private val screenRecordRepository =
+ ScreenRecordRepositoryImpl(
+ bgCoroutineContext = testScope.testScheduler,
+ recordingController = recordingController,
+ )
+
private val underTest =
ScreenRecordTileUserActionInteractor(
context,
testScope.testScheduler,
testScope.testScheduler,
+ screenRecordRepository,
recordingController,
keyguardInteractor,
keyguardDismissUtil,
diff --git a/packages/SystemUI/res/drawable/android15_patch_adaptive.xml b/packages/SystemUI/res/drawable/android15_patch_adaptive.xml
new file mode 100644
index 0000000..d949200
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android15_patch_adaptive.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/android15_patch_adaptive_background"/>
+ <foreground android:drawable="@drawable/android15_patch_adaptive_foreground"/>
+ <monochrome android:drawable="@drawable/android15_patch_monochrome"/>
+</adaptive-icon>
diff --git a/packages/SystemUI/res/drawable/android15_patch_adaptive_background.xml b/packages/SystemUI/res/drawable/android15_patch_adaptive_background.xml
new file mode 100644
index 0000000..d4850d3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android15_patch_adaptive_background.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <!-- space (themed version) -->
+ <path
+ android:pathData="M0,0h108v108h-108z"
+ android:fillColor="@android:color/system_neutral1_800"/>
+ <!-- stars (themed version) -->
+ <group>
+ <path
+ android:pathData="M32,34 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M33,61 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M71,34 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M62,56 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M68,47 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M72,55 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M39,36 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+
+ <path
+ android:pathData="M72,49 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M46,53 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M32,45 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M43,37 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M78,51 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M34,51 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M76,41 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M39,46 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/android15_patch_adaptive_foreground.xml b/packages/SystemUI/res/drawable/android15_patch_adaptive_foreground.xml
new file mode 100644
index 0000000..34f6ee0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android15_patch_adaptive_foreground.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+
+ <!-- zoomies (themed version) -->
+ <group>
+ <path
+ android:pathData="M53,42C52.21,50.58 46.46,68.95 32.11,74.63C19.22,79.75 5.77,82.32 1.19,83.19C0.68,83.29 0.28,83.36 0,83.42V108H54H108V83.42C107.72,83.36 107.32,83.29 106.81,83.19C102.23,82.32 88.78,79.75 75.89,74.63C61.54,68.95 55.79,50.58 55,42H54H53Z"
+ android:fillColor="@android:color/system_accent1_100"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M53.25,42C52.88,50.53 50.44,69.01 43.68,74.67C36.91,80.33 32.65,82.86 31.37,83.41L54,102.87L76.63,83.41C75.35,82.86 71.09,80.33 64.32,74.67C57.56,69.01 55.12,50.53 54.75,42H54H53.25Z"
+ android:fillColor="#ffffff"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M54,42m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#ffffff"/>
+ </group>
+ <group>
+ <!-- head! it's like sputnik -->
+ <path
+ android:pathData="M54,94.25m-26.25,0a26.25,26.25 0,1 1,52.5 0a26.25,26.25 0,1 1,-52.5 0"
+ android:fillColor="#34A853"/>
+ <!-- ant -->
+ <path
+ android:pathData="M38,63.5L44.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#34A853"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M70,63.5L63.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#34A853"
+ android:strokeLineCap="round"/>
+ </group>
+ <!-- spaceship -->
+ <path
+ android:pathData="M54,34C52.34,34 51,35.29 51,36.88V40.44C51,40.75 51.25,41 51.56,41C51.87,41 52.13,40.75 52.13,40.44V39.48C52.13,38.87 52.63,38.37 53.25,38.37H54.75C55.37,38.37 55.87,38.87 55.87,39.48V40.44C55.87,40.75 56.13,41 56.44,41C56.75,41 57,40.75 57,40.44V36.88C57,35.29 55.66,34 54,34H54Z"
+ android:fillColor="#E9F3EB"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/android15_patch_monochrome.xml b/packages/SystemUI/res/drawable/android15_patch_monochrome.xml
new file mode 100644
index 0000000..a91cc86
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android15_patch_monochrome.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <group>
+ <path
+ android:pathData="
+ M54,94.25
+ m-26.25,0
+ a26.25,26.25 0,1 1,52.5 0
+ a26.25,26.25 0,1 1,-52.5 0
+ "
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M38,63.5L44.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M70,63.5L63.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeLineCap="round"/>
+
+ <path
+ android:pathData="
+ M54,34
+ C52.34,34 51,35.29 51,36.88
+ V40.44
+ C51,40.75 51.25,41 51.56,41
+ C51.87,41 52.13,40.75 52.13,40.44
+ V39.48
+ C52.13,38.87 52.63,38.37 53.25,38.37
+ H54.75
+ C55.37,38.37 55.87,38.87 55.87,39.48
+ V40.44
+ C55.87,40.75 56.13,41 56.44,41
+ C56.75,41 57,40.75 57,40.44
+ V36.88
+ C57,35.29 55.66,34 54,34
+ H54
+ Z
+ "
+ android:fillColor="#34A853"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M54,40V67"
+ android:fillColor="#00000000"
+ android:strokeColor="#40FFFFFF"
+ />
+
+ <path
+ android:pathData="M32,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M33,61 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M71,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M62,56 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M68,47 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M72,55 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,36 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+
+ <path
+ android:pathData="M72,49 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M46,53 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M32,45 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M43,37 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M78,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M34,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M76,41 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,46 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c25d8cb..a7dfdaa 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Skakel dit môre outomaties weer aan"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Kenmerke soos Kitsdeel en Kry My Toestel gebruik Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth sal môreoggend aanskakel"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Oudiodeling"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Deel tans oudio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batterykrag"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Oudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Kopstuk"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Watter deel van jou toestelervaring is geraak?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Kies soort kwessie"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skermopname"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Werkverrigting"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Gebruikerkoppelvlak"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termies"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Eenhandmodus"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Gehoortoestelle"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktief"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Ontkoppel"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Gehoortoestelle"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Bind nuwe toestel saam"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nuwe toestel saam te bind"</string>
@@ -1201,7 +1198,7 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-fi sal vir nou nie outomaties koppel nie"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ontkoppel Ethernet om netwerke te wissel"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Om toestelervaring te verbeter, kan programme en dienste steeds enige tyd na wi‑fi-netwerke soek, selfs wanneer wi‑fi af is. Jy kan dit in Wi-fi-opsporinginstellings verander. "<annotation id="link">"Verander"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Om toestelervaring te verbeter, kan apps en dienste steeds enige tyd na wi‑fi-netwerke soek, selfs wanneer wi‑fi af is. Jy kan dit in Wi-fi-opsporinginstellings verander. "<annotation id="link">"Verander"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"Skakel vliegtuigmodus af"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wil die volgende teël by Kitsinstellings voeg"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Voeg teël by"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gevou"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"oopgevou"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stilusbattery <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Koppel jou stilus aan ’n laaier"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Stilus se battery is amper pap"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Soekkortpaaie"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Vou ikoon in"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vou ikoon uit"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Sleutelbordlig"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Vlak %1$d van %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Huiskontroles"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index ed6a3e1..396837e 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ነገ እንደገና በራስ-ሰር አስጀምር"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"እንደ ፈጣን ማጋራት እና የእኔን መሣሪያ አግኝ ያሉ ባህሪዎች ብሉቱዝን ይጠቀማሉ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ብሉቱዝ ነገ ጠዋት ይበራል"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"የድምጽ ማጋራት"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ድምጽን በማጋራት ላይ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ባትሪ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ኦዲዮ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ማዳመጫ"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"የትኛው የመሣሪያዎ ተሞክሮ ክፍል ተጎድቷል?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"የችግሩን አይነት ይምረጡ"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"የማያ መቅረጫ"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"አፈጻጸም"</string>
+ <string name="user_interface" msgid="3712869377953950887">"የተጠቃሚ በይነገፅ"</string>
+ <string name="thermal" msgid="6758074791325414831">"ተርማል"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"የአንድ እጅ ሁነታ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"የመስሚያ መሣሪያዎች"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ገቢር"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ግንኙነት ተቋርጧል"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"የመስማት ችሎታ መሣሪያ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"አዲስ መሣሪያ ያጣምሩ"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"አዲስ መሣሪያ ለማጣመር ጠቅ ያድርጉ"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"የታጠፈ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"የተዘረጋ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"የብሮስፌ ባትሪ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ብሮስፌዎን ከኃይል መሙያ ጋር ያገናኙ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"የብሮስፌ ባትሪ ዝቅተኛ ነው"</string>
<string name="video_camera" msgid="7654002575156149298">"የቪድዮ ካሜራ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"የፍለጋ አቋራጮች"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"መሰብሰቢያ አዶ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"መዘርጊያ አዶ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ወይም"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"የቁልፍ ሰሌዳ የጀርባ ብርሃን"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"ደረጃ %1$d ከ %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"የቤት ውስጥ ቁጥጥሮች"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1502765..254549f 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"تفعيل البلوتوث تلقائيًا مرة أخرى غدًا"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"يُستخدَم البلوتوث في ميزات مثل Quick Share و\"العثور على جهازي\""</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"سيتم تفعيل البلوتوث صباح الغد"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"مشاركة الصوت"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"مشاركة الصوت"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"مستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"صوت"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"سماعة الرأس"</string>
@@ -301,11 +303,11 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"المستخدم"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"الإنترنت"</string>
- <string name="quick_settings_networks_available" msgid="1875138606855420438">"الشبكات متوفرة"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"تتوفّر شبكات"</string>
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"الشبكات غير متوفرة"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"لا تتوفر أي شبكة Wi-Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"جارٍ التفعيل…"</string>
- <string name="quick_settings_cast_title" msgid="3033553249449938182">"الإرسال"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"البث"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"جارٍ الإرسال"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"جهاز لا يحمل اسمًا"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"لا يتوفر أي جهاز"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"الأداء الحراري"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"وضع \"التصفح بيد واحدة\""</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سماعات الأذن الطبية"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"متّصلة حاليًا"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"غير متّصلة"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سماعات الأذن الطبية"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"إقران جهاز جديد"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"انقر لإقران جهاز جديد"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"اختصارات طلبات البحث"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"رمز التصغير"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"رمز التوسيع"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"أو"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"الإضاءة الخلفية للوحة المفاتيح"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"مستوى الإضاءة: %1$d من %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"إدارة المنزل آليًّا"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 00d673e..dd71023 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"কাইলৈ পুনৰ স্বয়ংক্ৰিয়ভাৱে অন কৰক"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share আৰু Find My Deviceৰ দৰে সুবিধাসমূহে ব্লুটুথ ব্যৱহাৰ কৰে"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"কাইলৈ পুৱা ব্লুটুথ অন হ’ব"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"অডিঅ’ শ্বেয়াৰ কৰা"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"অডিঅ’ শ্বেয়াৰ কৰি থকা হৈছে"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"বেটাৰী <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"অডিঅ’"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"হেডছেট"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"থাৰ্মেল"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"এখন হাতেৰে ব্যৱহাৰ কৰা ম’ড"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"শুনাৰ ডিভাইচ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"সক্ৰিয় হৈ আছে"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"সংযোগ বিচ্ছিন্ন কৰা হ’ল"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"শুনাৰ ডিভাইচ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"নতুন ডিভাইচ পেয়াৰ কৰিবলৈ ক্লিক কৰক"</string>
@@ -1265,8 +1265,8 @@
<string name="rear_display_bottom_sheet_confirm" msgid="1507591562761552899">"এতিয়াই স্ক্ৰীন সলনি কৰক"</string>
<string name="rear_display_folded_bottom_sheet_title" msgid="3930008746560711990">"ফ’নটো আনফ’ল্ড কৰক"</string>
<string name="rear_display_unfolded_bottom_sheet_title" msgid="6291111173057304055">"স্ক্ৰীন সলনি কৰিবনে?"</string>
- <string name="rear_display_folded_bottom_sheet_description" msgid="6842767125783222695">"অধিক ৰিজ’লিউছনৰ বাবে, পিছফালৰ কেমেৰাটো ব্যৱহাৰ কৰক"</string>
- <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"অধিক ৰিজ’লিউছনৰ বাবে, ফ’নটো লুটিয়াই দিয়ক"</string>
+ <string name="rear_display_folded_bottom_sheet_description" msgid="6842767125783222695">"অধিক ৰিজ’লিউশ্বনৰ বাবে, পিছফালৰ কেমেৰাটো ব্যৱহাৰ কৰক"</string>
+ <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"অধিক ৰিজ’লিউশ্বনৰ বাবে, ফ’নটো লুটিয়াই দিয়ক"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"জপাব পৰা ডিভাইচৰ জাপ খুলি থকা হৈছে"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"জপাব পৰা ডিভাইচৰ ওলোটাই থকা হৈছে"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফ’ল্ড কৰা"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"সন্ধানৰ শ্বৰ্টকাট"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"সংকোচন কৰাৰ চিহ্ন"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"বিস্তাৰ কৰাৰ চিহ্ন"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"কীব’ৰ্ডৰ বেকলাইট"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dৰ %1$d স্তৰ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ঘৰৰ সা-সৰঞ্জামৰ নিয়ন্ত্ৰণ"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index b3c0058..592bc06 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Sabah avtomatik aktiv edin"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Cəld Paylaşım və Cihazın Tapılması kimi funksiyalar Bluetooth istifadə edir"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth sabah səhər aktiv ediləcək"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio paylaşma"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audio paylaşılır"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batareya"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Qulaqlıq"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cihaz istifadəsinə necə təsir etdi?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Problem növü seçin"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran qeydəalma"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performans"</string>
+ <string name="user_interface" msgid="3712869377953950887">"İstifadəçi interfeysi"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Birəlli rejim"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Eşitmə cihazları"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktiv"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Bağlantı kəsildi"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Eşitmə cihazları"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yeni cihaz birləşdirin"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz birləşdirmək üçün klikləyin"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"qatlanmış"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"açıq"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stilusun enerjisi: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Qələmi adapterə qoşun"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Qələm enerjisi azdır"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Axtarış qısayolları"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"İkonanı yığcamlaşdırın"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"İkonanı genişləndirin"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"və ya"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura işığı"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Səviyyə %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Ev nizamlayıcıları"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 22afb40..9b27943 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatski ponovo uključi sutra"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkcije kao što su Quick Share i Pronađi moj uređaj koriste Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth će se uključiti sutra ujutru"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Deljenje zvuka"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Deli se zvuk"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Nivo baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Termalna kamera"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jednom rukom"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni aparati"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivno"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Veza je prekinuta"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni aparati"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Upari novi uređaj"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili nov uređaj"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečice pretrage"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za skupljanje"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvetljenje tastature"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrole za dom"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 4fe7c5a..ca763cf 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Аўтаматычнае ўключэнне заўтра"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth выкарыстоўваецца такімі функцыямі і сэрвісамі, як Хуткае абагульванне і Знайсці прыладу"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth уключыцца заўтра раніцай"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Абагульванне аўдыя"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Ідзе абагульванне аўдыя"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Узровень зараду: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Гук"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнітура"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"З чым была звязана праблема, якая вам сустрэлася?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Выберыце тып праблемы"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запіс экрана"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Прадукцыйнасць"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Карыстальніцкі інтэрфейс"</string>
+ <string name="thermal" msgid="6758074791325414831">"Тэрмальныя паказчыкі"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Рэжым кіравання адной рукой"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слыхавыя апараты"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Актыўныя"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Адключаны"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слыхавыя апараты"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Спалучыць новую прыладу"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Націсніце, каб спалучыць новую прыладу"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складзена"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"раскладзена"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Зарад акумулятара пяра – <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Падключыце пяро да зараднай прылады"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Нізкі ўзровень зараду пяра"</string>
<string name="video_camera" msgid="7654002575156149298">"Відэакамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пошук спалучэнняў клавіш"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Згарнуць\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Разгарнуць\""</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Падсветка клавіятуры"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Узровень %1$d з %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Кіраванне домам"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 2cd65db..d50b116 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Автоматично включване отново утре"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Функции като „Бързо споделяне“ и „Намиране на устройството ми“ използват Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ще се включи утре сутрин"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Споделяне на звука"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Звукът се споделя"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батерия: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Слушалки"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"С какво имахте проблем?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изберете тип проблем"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запис на екрана"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Ефективност"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Потребителски интерфейс"</string>
+ <string name="thermal" msgid="6758074791325414831">"Термално"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим за работа с една ръка"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слухови апарати"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Активно"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Няма връзка"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухови апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Сдвояване на ново устройство"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликнете за сдвояване на ново устройство"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворено"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворено"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Батерия на писалката: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Свържете писалката към зарядно устройство"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Батерията на писалката е изтощена"</string>
<string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Търсете клавишни комбинации"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за свиване"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за разгъване"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Подсветка на клавиатурата"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Ниво %1$d от %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Контроли за дома"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index f8e350a..bb41b1b 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"আগামীকাল আবার অটোমেটিক চালু হবে"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"দ্রুত শেয়ার ও Find My Device-এর মতো ফিচার ব্লুটুথ ব্যবহার করে"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ব্লুটুথ আগামীকাল সকালে চালু হয়ে যাবে"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"অডিও শেয়ারিং"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"অডিও শেয়ার করা হচ্ছে"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"চার্জ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"অডিও"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"হেডসেট"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ডিভাইস ব্যবহার করার সময় কোথায় অসুবিধা হয়েছিল?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"সমস্যার প্রকার বেছে নিন"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"স্ক্রিন রেকর্ড"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"পারফর্ম্যান্স"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ইউজার ইন্টারফেস"</string>
+ <string name="thermal" msgid="6758074791325414831">"থার্মাল"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"এক হাতে ব্যবহার করার মোড"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"হিয়ারিং ডিভাইস"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"অ্যাক্টিভ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ডিসকানেক্ট হয়ে গেছে"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"হিয়ারিং ডিভাইস"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"নতুন ডিভাইস পেয়ার করুন"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"নতুন ডিভাইস পেয়ার করতে ক্লিক করুন"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফোল্ড করা রয়েছে"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ফোল্ড করা নেই"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"স্টাইলাস ব্যাটারি <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"কোনও চার্জারের সাথে আপনার স্টাইলাস কানেক্ট করুন"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"স্টাইলাস ব্যাটারিতে চার্জ কম আছে"</string>
<string name="video_camera" msgid="7654002575156149298">"ভিডিও ক্যামেরা"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"সার্চ শর্টকাট"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"আইকন আড়াল করুন"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"আইকন বড় করুন"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"কীবোর্ড ব্যাকলাইট"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-এর মধ্যে %1$d লেভেল"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"হোম কন্ট্রোল"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 60c936e..4916d80 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatski uključi ponovo sutra"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkcije kao što su Quick Share i Pronađi moj uređaj koriste Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth će se uključiti sutra ujutro"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Dijeljenje zvuka"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Dijeljenje zvuka"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> baterije"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Koji dio uređaja je imao problem?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Odaberite vrstu problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje ekrana"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performanse"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Korisnički interfejs"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termalno"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Način rada jednom rukom"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni aparati"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivno"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Veza je prekinuta"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni aparati"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparite novi uređaj"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da uparite novi uređaj"</string>
@@ -1201,7 +1198,7 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi se trenutno ne može automatski povezati"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da promijenite mrežu, isključite ethernet"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Radi poboljšanja iskustva s uređajem aplikacije i usluge i dalje mogu tražiti WiFi mreže bilo kada, čak i kada je WiFi isključen. Ovo možete promijeniti u Postavkama traženja WiFi mreže. "<annotation id="link">"Promijeni"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Radi poboljšanja iskustva s uređajem aplikacije i usluge i dalje mogu tražiti WiFi mreže bilo kada, čak i kada je WiFi isključen. Ovo možete promijeniti u postavkama traženja WiFi-ja. "<annotation id="link">"Promijeni"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"Isključi način rada u avionu"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> želi dodati sljedeću karticu u Brze postavke"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj karticu"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# aplikacija je aktivna}one{# aplikacija je aktivna}few{# aplikacije su aktivne}other{# aplikacija je aktivno}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nove informacije"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivne aplikacije"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ove aplikacije su aktivne i pokrenute, čak i kada ih ne koristite. Ovim se poboljšava njihova funkcionalnost, ali može uticati i na vijek trajanja baterije."</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ove aplikacije su aktivne i pokrenute, čak i kada ih ne koristite. Ovim se poboljšava njihova funkcionalnost, ali to može uticati i na vijek trajanja baterije."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zaustavljeno"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gotovo"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sklopljeno"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otklopljeno"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Baterija pisaljke <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Priključite pisaljku na punjač"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Baterija pisaljke je slaba"</string>
<string name="video_camera" msgid="7654002575156149298">"Video kamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečica pretraživanja"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sužavanja"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona proširivanja"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tastature"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrole za dom"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index a82d6f1..5afad1b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Torna\'l a activar automàticament demà"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Les funcions com Quick Share i Troba el meu dispositiu utilitzen el Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"El Bluetooth s\'activarà demà al matí"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Compartició d\'àudio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"S\'està compartint l\'àudio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de bateria"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Àudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculars"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"L\'experiència amb el dispositiu s\'ha vist afectada?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona el tipus de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravació de pantalla"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Rendiment"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interfície d\'usuari"</string>
+ <string name="thermal" msgid="6758074791325414831">"Tèrmic"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode d\'una mà"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Audiòfons"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Actiu"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconnectat"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Audiòfons"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincula un dispositiu nou"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fes clic per vincular un dispositiu nou"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegat"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegat"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria del llapis òptic: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connecta el llapis òptic a un carregador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria del llapis òptic baixa"</string>
<string name="video_camera" msgid="7654002575156149298">"Càmera de vídeo"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Dreceres de cerca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Replega la icona"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Desplega la icona"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroil·luminació del teclat"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivell %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controls de la llar"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 9b540ff..b5293c0 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Zítra znovu automaticky zapnout"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth využívají funkce jako Quick Share a Najdi moje zařízení."</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth se zapne zítra ráno."</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Sdílení zvuku"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sdílení zvuku"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterie: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Sluchátka"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Co v zařízení bylo ovlivněno?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vyberte druh problém"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Záznam obrazovky"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Výkon"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Uživatelské rozhraní"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termovize"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jedné ruky"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Naslouchátka"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivní"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Odpojeno"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Naslouchátka"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Spárovat nové zařízení"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zařízení"</string>
@@ -923,7 +920,7 @@
<string name="mobile_data" msgid="4564407557775397216">"Mobilní data"</string>
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
- <string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi je vypnuta"</string>
+ <string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi je vypnutá"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth je vypnuto"</string>
<string name="dnd_is_off" msgid="3185706903793094463">"Režim Nerušit je vypnut"</string>
<string name="dnd_is_on" msgid="7009368176361546279">"Režim Nerušit je zapnutý"</string>
@@ -933,7 +930,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikace běžící na pozadí"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Klepnutím zobrazíte podrobnosti o využití baterie a dat"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vypnout mobilní data?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Prostřednictvím <xliff:g id="CARRIER">%s</xliff:g> nebudete moci používat data ani internet. Internet bude dostupný pouze přes Wi-Fi."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Prostřednictvím operátora <xliff:g id="CARRIER">%s</xliff:g> nebudete moct používat data ani internet. Internet bude dostupný pouze přes Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"vašeho operátora"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"Přepnout zpět na operátora <xliff:g id="CARRIER">%s</xliff:g>?"</string>
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"Mobilní data se nebudou automaticky přepínat podle dostupnosti"</string>
@@ -1211,7 +1208,7 @@
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nové informace"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivní aplikace"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Tyto aplikace jsou spuštěné a aktivní, i když je nepoužíváte. Zlepšuje to jejich funkčnost, ale může to mít dopad na výdrž baterie."</string>
- <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Konec"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zastavit"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zastaveno"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Hotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Zkopírováno"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"složené"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Baterie dotykového pera <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Připojte dotykové pero k nabíječce"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Slabá baterie dotykového pera"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Vyhledat zkratky"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sbalení"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalení"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"nebo"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvícení klávesnice"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Úroveň %1$d z %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Ovládání domácnosti"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 57353f7..6e2323b 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Aktivér automatisk igen i morgen"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funktioner som f.eks. Quick Share og Find min enhed anvender Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth aktiveres i morgen tidlig"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Lyddeling"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Deler lyd"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batteri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvilken del af din enhedsoplevelse blev påvirket?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vælg problemtype"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skærmoptagelse"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Ydeevne"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Brugerflade"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termisk"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndstilstand"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Høreapparater"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivt"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Afbrudt"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Høreapparater"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Par ny enhed"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik for at parre en ny enhed"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"foldet"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"foldet ud"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batteriniveau på styluspen: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Slut din styluspen til en oplader"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Lavt batteriniveau på styluspen"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Genveje til søgning"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon for Skjul"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon for Udvid"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturets baggrundslys"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d af %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Hjemmestyring"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index e7fa9b1..bf28a88 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Morgen automatisch wieder aktivieren"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funktionen wie „Quick Share“ und „Mein Gerät finden“ verwenden Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth wird morgen früh aktiviert"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audiofreigabe"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audioinhalte werden freigegeben"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akkustand: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Welche Bereiche des Geräts waren betroffen?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Art des Problems auswählen"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Bildschirmaufnahme"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Leistung"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Benutzeroberfläche"</string>
+ <string name="thermal" msgid="6758074791325414831">"Überhitzung"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhandmodus"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hörgeräte"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktiv"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Nicht verbunden"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hörgeräte"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Neues Gerät koppeln"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicken, um neues Gerät zu koppeln"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zugeklappt"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aufgeklappt"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Akkustand des Eingabestifts: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Schließe deinen Eingabestift an ein Ladegerät an"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Stylus-Akkustand niedrig"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tastenkürzel suchen"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Symbol „Minimieren“"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Symbol „Maximieren“"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oder"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturbeleuchtung"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d von %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Smart-Home-Steuerung"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 23d704d..3dd5fc0 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Αυτόματη ενεργοποίηση ξανά αύριο"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Λειτουργίες όπως το Quick Share και η Εύρεση συσκευής χρησιμοποιούν το Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Το Bluetooth θα ενεργοποιηθεί αύριο το πρωί"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Κοινή χρήση ήχου"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Κοινή χρήση ήχου"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Μπαταρία <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ήχος"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ακουστικά"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ποιο κομμάτι της εμπειρίας συσκευής επηρεάστηκε;"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Επιλογή τύπου προβλήματος"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Εγγραφή οθόνης"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Απόδοση"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Διεπαφή χρήστη"</string>
+ <string name="thermal" msgid="6758074791325414831">"Θερμικό"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Λειτουργία ενός χεριού"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Συσκευές ακοής"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ενεργά"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Αποσυνδεδεμένα"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Συσκευές ακοής"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Σύζευξη νέας συσκευής"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Κάντε κλικ για σύζευξη νέας συσκευής"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"διπλωμένη"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ξεδιπλωμένη"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Μπαταρία γραφίδας <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Συνδέστε τη γραφίδα σε έναν φορτιστή"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Χαμηλή στάθμη μπαταρίας γραφίδας"</string>
<string name="video_camera" msgid="7654002575156149298">"Βιντεοκάμερα"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Συντομεύσεις αναζήτησης"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Εικονίδιο σύμπτυξης"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Εικονίδιο ανάπτυξης"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ή"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Οπίσθιος φωτισμός πληκτρολογίου"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Επίπεδο %1$d από %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Οικιακοί έλεγχοι"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index d71ff1c..e830f3c 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatically turn on again tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio sharing"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sharing audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Thermal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Active"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Disconnected"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 44e9d25..046ce28 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -281,8 +281,8 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatically turn on again tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio Sharing"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sharing Audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Share audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Sharing audio"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -1322,8 +1322,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home Controls"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index d71ff1c..e830f3c 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatically turn on again tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio sharing"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sharing audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Thermal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Active"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Disconnected"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index d71ff1c..e830f3c 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatically turn on again tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio sharing"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sharing audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Thermal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Active"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Disconnected"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index c2f7098..07907a6 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -281,8 +281,8 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatically turn on again tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio Sharing"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sharing Audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Share audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Sharing audio"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -1322,8 +1322,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home Controls"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index fd800ad..c622ebe 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Activar automáticamente mañana"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Las funciones como Quick Share y Encontrar mi dispositivo usan Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"El Bluetooth se activará mañana a la mañana"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Uso compartido de audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Compartiendo audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batería"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"¿Qué parte de tu exp. del disp. se vio afectada?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Seleccionar tipo de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Grabadora de pant."</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Rendimiento"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interfaz de usuario"</string>
+ <string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo una mano"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Activos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconectados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular dispositivo nuevo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para vincular un dispositivo nuevo"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batería de la pluma stylus: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta tu pluma stylus a un cargador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"La pluma stylus tiene poca batería"</string>
<string name="video_camera" msgid="7654002575156149298">"Videocámara"</string>
@@ -1328,10 +1324,9 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Buscar combinaciones de teclas"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícono de contraer"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícono de expandir"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controles de la casa"</string>
- <string name="home_controls_dream_description" msgid="4644150952104035789">"Accede rápidamente a controles de la casa como prot. de pantalla"</string>
+ <string name="home_controls_dream_description" msgid="4644150952104035789">"Usa rápidamente los controles de la casa como protector de pantalla"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 5bcf582..c021b45 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Volver a activar automáticamente mañana"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Las funciones como Quick Share y Encontrar mi dispositivo usan Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"El Bluetooth se activará mañana por la mañana"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Compartir audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Compartiendo audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batería"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"¿Qué parte de tu experiencia se ha visto afectada?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona el tipo de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Grabar pantalla"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Rendimiento"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interfaz de usuario"</string>
+ <string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo Una mano"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Audífonos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Activos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconectados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Audífonos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Emparejar nuevo dispositivo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para emparejar un nuevo dispositivo"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batería del lápiz óptico al <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta tu lápiz óptico a un cargador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Batería del lápiz óptico baja"</string>
<string name="video_camera" msgid="7654002575156149298">"Videocámara"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atajos de búsqueda"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icono de contraer"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icono de desplegar"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controles de la casa"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index e7d5e2f..003c925 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Lülita automaatselt homme uuesti sisse"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Sellised funktsioonid nagu Kiirjagamine ja Leia mu seade kasutavad Bluetoothi."</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth lülitub sisse homme hommikul"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Heli jagamine"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Heli jagamine"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> akut"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Heli"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Peakomplekt"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Millist seadme kasutuskogemuse osa see mõjutas?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Valige probleemi tüüp"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekraanisalvestus"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Jõudlus"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Kasutajaliides"</string>
+ <string name="thermal" msgid="6758074791325414831">"Soojus"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Ühekäerežiim"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Kuuldeseadmed"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ühendatud"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Ühendus on katkestatud"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Kuuldeseadmed"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uue seadme sidumine"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Uue seadme sidumiseks klõpsake"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kokku volditud"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"lahti volditud"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Elektronpliiatsi aku <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ühendage elektronpliiats laadijaga"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Elektronpliiatsi akutase on madal"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokaamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Otsingu otseteed"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ahendamisikoon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laiendamisikoon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"või"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatuuri taustavalgustus"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Tase %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kodu juhtelemendid"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 5e4c5ac..66b79b8 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Aktibatu automatikoki berriro bihar"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share, Bilatu nire gailua eta beste eginbide batzuek Bluetootha erabiltzen dute"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bihar goizean aktibatuko da Bluetootha"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audioa partekatzea"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audioa partekatzen"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audioa"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Entzungailua"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Gailuaren erabileraren zer alderdiri eragin dio?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Hautatu arazo mota"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Pantaila-grabaketa"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Errendimendua"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Erabiltzaile-interfazea"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termikoa"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Esku bakarreko modua"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Entzumen-gailuak"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktibo"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Deskonektatuta"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Entzumen-gailuak"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parekatu beste gailu bat"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Egin klik beste gailu bat parekatzeko"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"tolestuta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tolestu gabe"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Arkatzaren bateria: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Konektatu arkatza kargagailu batera"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Arkatzak bateria gutxi du"</string>
<string name="video_camera" msgid="7654002575156149298">"Bideokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Bilatu lasterbideak"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tolesteko ikonoa"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Zabaltzeko ikonoa"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"edo"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Teklatuaren hondoko argia"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d/%2$d maila"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Etxeko gailuen kontrola"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ad24c1b..cdbb685 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"فردا دوباره بهطور خودکار روشن شود"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ویژگیهایی مثل «همرسانی سریع» و «پیدا کردن دستگاهم» از بلوتوث استفاده میکنند"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"بلوتوث فردا صبح روشن خواهد شد"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"اشتراک صدا"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"درحال اشتراکگذاری صدا"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"شارژ باتری <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"صوت"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"هدست"</string>
@@ -361,24 +363,19 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"کدام بخش تجربه استفاده از دستگاه تحتتأثیر قرار گرفت؟"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"انتخاب نوع مشکل"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ضبط صفحهنمایش"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"عملکرد"</string>
+ <string name="user_interface" msgid="3712869377953950887">"میانای کاربر"</string>
+ <string name="thermal" msgid="6758074791325414831">"حرارتی"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"حالت یکدستی"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سمعک"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"فعال"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"اتصال قطع شد"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سمعک"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"جفت کردن دستگاه جدید"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"برای جفت کردن دستگاه جدید، کلیک کنید"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"پیشتنظیم بهروزرسانی نشد"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"پیشتنظیم"</string>
- <string name="live_caption_title" msgid="8916875614623730005">"زیرنویس زنده"</string>
+ <string name="live_caption_title" msgid="8916875614623730005">"زیرنویس ناشنوایان زنده"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"میکروفون دستگاه لغو انسداد شود؟"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"دوربین دستگاه لغو انسداد شود؟"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"دوربین و میکروفون دستگاه لغو انسداد شود؟"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"تاشده"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"تانشده"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"شارژ باتری قلم <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"قلم را به شارژر وصل کنید"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"باتری قلم ضعیف است"</string>
<string name="video_camera" msgid="7654002575156149298">"دوربین ویدیویی"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"جستجوی میانبرها"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"نماد جمع کردن"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"نماد ازهم بازکردن"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"نور پسزمینه صفحهکلید"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"سطح %1$d از %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"کنترل خانه هوشمند"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 0fed3d5..bea39cb 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Laita automaattisesti päälle taas huomenna"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share, Paikanna laite ja tietyt muut ominaisuudet käyttävät Bluetoothia"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth menee päälle huomisaamuna"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audionjako"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audiota jaetaan"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akun taso <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ääni"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Mitä osaa käyttökokemuksesta ongelma koski?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Valitse ongelman tyyppi"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Näytön tallentaja"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Suorituskyky"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Käyttöliittymä"</string>
+ <string name="thermal" msgid="6758074791325414831">"Lämpökamera"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Yhden käden moodi"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Kuulolaitteet"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktiivinen"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Yhteys katkaistu"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Kuulolaitteet"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Muodosta uusi laitepari"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Muodosta uusi laitepari klikkaamalla"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"taitettu"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"taittamaton"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Näyttökynän akku <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Yhdistä näyttökynä laturiin"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Näyttökynän akku vähissä"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pikahaut"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tiivistyskuvake"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laajennuskuvake"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"tai"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Näppämistön taustavalo"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Taso %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kodin ohjaus"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 95c788a..95b25936 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Activer le Bluetooth automatiquement demain"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Les fonctionnalités comme Partage rapide et Localiser mon appareil utilisent le Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Le Bluetooth s\'activera demain matin"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Partage audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Partage de l\'audio en cours…"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Écouteurs"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quelle composante de l\'appareil a été affectée?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sélectionner un type"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Enregistrement écran"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performance"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interface utilisateur"</string>
+ <string name="thermal" msgid="6758074791325414831">"Thermique"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode Une main"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Appareils auditifs"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Actives"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Déconnectées"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Appareils auditifs"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Associer un nouvel appareil"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquez ici pour associer un nouvel appareil"</string>
@@ -1209,8 +1206,8 @@
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir l\'utilisateur"</string>
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# application est active}one{# application est active}many{# d\'applications sont actives}other{# applications sont actives}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nouvelle information"</string>
- <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applications actives"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ces applications sont actives et s\'exécutent même lorsque vous ne les utilisez pas. Cela améliore leur fonctionnalité, mais peut également affecter l\'autonomie de la pile."</string>
+ <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applis actives"</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ces applis sont actives et s\'exécutent même lorsque vous ne les utilisez pas. Cela améliore leur fonctionnalité, mais peut également affecter l\'autonomie de la pile."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Arrêtée"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"OK"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Pile du stylet <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connectez votre stylet à un chargeur"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Pile du stylet faible"</string>
<string name="video_camera" msgid="7654002575156149298">"Caméra"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Recherchez des raccourcis"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Domotique"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b7abd0e..1b8ddc1 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Réactiver automatiquement demain"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Certaines fonctionnalités, telles que Quick Share et Localiser mon appareil, utilisent le Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Le Bluetooth sera activé demain matin"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Partage audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audio partagé"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batterie"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Casque"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quel problème avez-vous rencontré avec votre appareil ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sélectionnez un type de problème"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Enregistrement de l\'écran"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performances"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interface utilisateur"</string>
+ <string name="thermal" msgid="6758074791325414831">"Thermique"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode une main"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Appareils auditifs"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Actifs"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Déconnectés"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Appareils auditifs"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Associer un nouvel appareil"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquer pour associer un nouvel appareil"</string>
@@ -1212,7 +1209,7 @@
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applis actives"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ces applis sont actives et s\'exécutent même lorsque vous ne les utilisez pas. Cela améliore leur fonctionnement, mais peut également affecter l\'autonomie de la batterie."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
- <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Arrêtée"</string>
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Arrêté"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"OK"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copié"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batterie du stylet à <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connectez votre stylet à un chargeur"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"La batterie du stylet est faible"</string>
<string name="video_camera" msgid="7654002575156149298">"Caméra"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Raccourcis de recherche"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d sur %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Contrôle de la maison"</string>
diff --git a/packages/SystemUI/res/values-fr/tiles_states_strings.xml b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
index 23c124c..fcdd9f0 100644
--- a/packages/SystemUI/res/values-fr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
@@ -58,8 +58,8 @@
</string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"Indisponible"</item>
- <item msgid="5044688398303285224">"Désactivée"</item>
- <item msgid="8527389108867454098">"Activée"</item>
+ <item msgid="5044688398303285224">"Désactivé"</item>
+ <item msgid="8527389108867454098">"Activé"</item>
</string-array>
<string-array name="tile_states_rotation">
<item msgid="4578491772376121579">"Indisponible"</item>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 55dd05a..1d0f4c4 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Volver activar automaticamente mañá"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"As funcións como Quick Share e Localizar o meu dispositivo utilizan o Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"O Bluetooth activarase mañá á mañá"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio compartido"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Compartindo audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batería"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cal foi o problema na experiencia co dispositivo?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona o tipo de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravación de pant."</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Rendemento"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interface de usuario"</string>
+ <string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo dunha soa man"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Activos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconectados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular dispositivo novo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic para vincular un novo dispositivo"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"dispositivo pregado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dispositivo despregado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batería do lapis óptico: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta o lapis óptico a un cargador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"O lapis óptico ten pouca batería"</string>
<string name="video_camera" msgid="7654002575156149298">"Videocámara"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atallos de busca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona de contraer"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona de despregar"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación do teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controis domóticos"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 425a768..7a4cfd1 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"આવતીકાલે ફરીથી ઑટોમૅટિક રીતે ચાલુ કરો"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ક્વિક શેર અને Find My Device જેવી સુવિધાઓ બ્લૂટૂથનો ઉપયોગ કરે છે"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"બ્લૂટૂથ આવતીકાલે સવારે ચાલુ થશે"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ઑડિયો શેરિંગ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ઑડિયો શેર કરી રહ્યાં છીએ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> બૅટરી"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ઑડિયો"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"હૅડસેટ"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ડિવાઇસ સંબંધી તમારા અનુભવના કયા ભાગને અસર થઈ હતી?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"સમસ્યાનો પ્રકાર પસંદ કરો"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"સ્ક્રીન રેકોર્ડ કરો"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"પર્ફોર્મન્સ"</string>
+ <string name="user_interface" msgid="3712869377953950887">"યૂઝર ઇન્ટરફેસ"</string>
+ <string name="thermal" msgid="6758074791325414831">"થર્મલ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"એક-હાથે વાપરો મોડ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"સાંભળવામાં મદદ આપતા ડિવાઇસ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"સક્રિય"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ડિસ્કનેક્ટેડ છે"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"સાંભળવામાં મદદ આપતા ડિવાઇસ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"નવા ડિવાઇસ સાથે જોડાણ કરવા માટે ક્લિક કરો"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ફોલ્ડ કરેલું"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"અનફોલ્ડ કરેલું"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"સ્ટાઇલસની બૅટરી <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"તમારા સ્ટાઇલસને ચાર્જર સાથે કનેક્ટ કરો"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"સ્ટાઇલસની બૅટરીમાં ચાર્જ ઓછો છે"</string>
<string name="video_camera" msgid="7654002575156149298">"વીડિયો કૅમેરા"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"શૉર્ટકટ શોધો"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\'નાનું કરો\'નું આઇકન"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\'મોટું કરો\'નું આઇકન"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"અથવા"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"કીબોર્ડની બૅકલાઇટ"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dમાંથી %1$d લેવલ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ઘરેલું સાધનોના નિયંત્રણો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 8f7b87c..896af24 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"कल फिर से अपने-आप चालू हो जाए"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"क्विक शेयर और Find My Device जैसी सुविधाएं, ब्लूटूथ का इस्तेमाल करती हैं"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ब्लूटूथ कल सुबह चालू होगा"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ऑडियो शेयर करने की सुविधा"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ऑडियो शेयर किया जा रहा है"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> बैटरी"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ऑडियो"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"आपके डिवाइस की कौनसी सुविधा पर असर पड़ा था?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्या का टाइप चुनें"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रीन रिकॉर्डर"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"परफ़ॉर्मेंस"</string>
+ <string name="user_interface" msgid="3712869377953950887">"यूज़र इंटरफ़ेस"</string>
+ <string name="thermal" msgid="6758074791325414831">"थर्मल"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"वन-हैंडेड मोड"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"कान की मशीनें"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ऐक्टिव"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"डिसकनेक्ट हो गया"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"कान की मशीनें"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नया डिवाइस जोड़ें"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नया डिवाइस जोड़ने के लिए क्लिक करें"</string>
@@ -1112,7 +1109,7 @@
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> डिवाइस चुने गए"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिसकनेक्ट हो गया)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"स्विच नहीं किया जा सकता. फिर से कोशिश करने के लिए टैप करें."</string>
- <string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"किसी डिवाइस को कनेक्ट करें"</string>
+ <string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"कोई डिवाइस कनेक्ट करें"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"इस सेशन को कास्ट करने के लिए, कृपया ऐप्लिकेशन खोलें."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अनजान ऐप्लिकेशन"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट करना बंद करें"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"डिवाइस फ़ोल्ड किया गया"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"डिवाइस अनफ़ोल्ड किया गया"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"स्टाइलस की बैटरी <xliff:g id="PERCENTAGE">%s</xliff:g> है"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"अपने स्टाइलस को चार्ज करें"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलस की बैटरी कम है"</string>
<string name="video_camera" msgid="7654002575156149298">"वीडियो कैमरा"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"सर्च शॉर्टकट"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"छोटा करने का आइकॉन"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"बड़ा करने का आइकॉन"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"या"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड की बैकलाइट"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d में से %1$d लेवल"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index bc84c1d..acf253d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatski uključi ponovno sutra"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Značajke kao što su brzo dijeljenje i Pronađi moj uređaj koriste Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth će se uključiti sutra ujutro"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Zajedničko slušanje"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Zajedničko slušanje"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> baterije"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na koji dio doživljaja na uređaju to utjecalo?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Odaberite vrstu problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje zaslona"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Izvedba"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Korisničko sučelje"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termalno"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Način rada jednom rukom"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušna pomagala"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivno"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Nije povezano"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušna pomagala"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparite novi uređaj"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili novi uređaj"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zatvoreno"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otvoreno"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Baterija olovke <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Priključite pisaljku na punjač"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Slaba baterija pisaljke"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečaci za pretraživanje"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za sažimanje"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tipkovnice"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Razina %1$d od %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Upravljanje uređajima"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4b36026..c73511e 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatikus visszakapcsolás holnap"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Egyes funkciók (például a Quick Share és a Készülékkereső) Bluetootht használnak"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"A Bluetooth holnap reggel bekapcsol"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Hang megosztása"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Hang megosztása…"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akkumulátor: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Hang"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -292,7 +294,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatikus elforgatás"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatikus képernyőforgatás"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Tartózkodási hely"</string>
- <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Képernyővédő"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Képernyőkímélő"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Hozzáférés a kamerához"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonelérés"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Rendelkezésre áll"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Az eszközhasználati élmény mely része érintett?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Problématípus kiválasztása"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Képernyőrögzítés"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Teljesítmény"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Kezelőfelület"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termikus"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Egykezes mód"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hallókészülékek"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktív"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Leválasztva"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hallókészülékek"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Új eszköz párosítása"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kattintson új eszköz párosításához"</string>
@@ -601,7 +598,7 @@
<string name="screen_pinning_exit" msgid="4553787518387346893">"Alkalmazás kitűzése megszüntetve"</string>
<string name="stream_voice_call" msgid="7468348170702375660">"Telefonhívás"</string>
<string name="stream_system" msgid="7663148785370565134">"Rendszer"</string>
- <string name="stream_ring" msgid="7550670036738697526">"Csörgetés"</string>
+ <string name="stream_ring" msgid="7550670036738697526">"Csörgés"</string>
<string name="stream_music" msgid="2188224742361847580">"Média"</string>
<string name="stream_alarm" msgid="16058075093011694">"Ébresztő"</string>
<string name="stream_notification" msgid="7930294049046243939">"Értesítés"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"összehajtva"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kihajtva"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Érintőceruza töltöttségi szintje: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Tegye töltőre az érintőceruzát"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Az érintőceruza töltöttsége alacsony"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Billentyűparancsok keresése"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Összecsukás ikon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kibontás ikon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vagy"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"A billentyűzet háttérvilágítása"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Fényerő: %2$d/%1$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Otthon vezérlése"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index d8e36ad..f1462be 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Վաղը նորից ավտոմատ միացնել"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth-ն օգտագործում են, օրինակ, Quick Share և «Գտնել իմ սարքը» գործառույթները"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth-ը կմիանա վաղն առավոտյան"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Աուդիոյի փոխանցում"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Աուդիոն փոխանցվում է"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Աուդիո"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ականջակալ"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Սարքի ո՞ր մասի հետ է կապված խնդիրը։"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Ընտրեք խնդրի տեսակը"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Էկրանի տեսագրում"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Արդյունավետություն"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Օգտատիրական ինտերֆեյս"</string>
+ <string name="thermal" msgid="6758074791325414831">"Ջերմատեսիլ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Մեկ ձեռքի ռեժիմ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Լսողական սարքեր"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ակտիվ է"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Անջատված է"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Լսողական սարքեր"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Նոր սարքի զուգակցում"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Սեղմեք՝ նոր սարք զուգակցելու համար"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ծալված"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"բացված"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Ստիլուսի մարտկոցի լիցքը՝ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ձեր ստիլուսը միացրեք լիցքավորիչի"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Ստիլուսի մարտկոցի լիցքի ցածր մակարդակ"</string>
<string name="video_camera" msgid="7654002575156149298">"Տեսախցիկ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Դյուրանցումների որոնում"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ծալել պատկերակը"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ծավալել պատկերակը"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"կամ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Հետին լուսավորությամբ ստեղնաշար"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d՝ %2$d-ից"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Տան կառավարման տարրեր"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 22d0de5..7525e9a 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Otomatis aktifkan lagi besok"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Fitur seperti Quick Share dan Temukan Perangkat Saya menggunakan Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth akan dinyalakan besok pagi"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Berbagi Audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Berbagi Audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Bagian pengalaman perangkat mana yang terpengaruh?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pilih jenis masalah"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Perekaman layar"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performa"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Antarmuka Pengguna"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode satu tangan"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Alat bantu dengar"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktif"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Terputus"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Alat bantu dengar"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sambungkan perangkat baru"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menyambungkan perangkat baru"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ditutup"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dibuka"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Baterai stilus <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Hubungkan stilus ke pengisi daya"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Baterai stilus lemah"</string>
<string name="video_camera" msgid="7654002575156149298">"Kamera video"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan penelusuran"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon ciutkan"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon luaskan"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Lampu latar keyboard"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Tingkat %1$d dari %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrol Rumah"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index b631c47..3850790 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Kveikja sjálfkrafa aftur á morgun"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Eiginleikar eins og Flýtideiling og Finna tækið mitt nota Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Kveikt verður á Bluetooth í fyrramálið"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Hljóði deilt"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Deilir hljóði"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> rafhlöðuhleðsla"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Hljóð"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Höfuðtól"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvað í tækjaupplifuninni varð fyrir áhrifum?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Veldu gerð vandamáls"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skjáupptaka"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Afköst"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Notandaviðmót"</string>
+ <string name="thermal" msgid="6758074791325414831">"Varmi"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhent stilling"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Heyrnartæki"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Virk"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Aftengd"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Heyrnartæki"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Para nýtt tæki"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Smelltu til að para nýtt tæki"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"samanbrotið"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"opið"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Pennarafhlaða <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Tengdu pennann við hleðslutæki"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Rafhlaða pennans er að tæmast"</string>
<string name="video_camera" msgid="7654002575156149298">"Kvikmyndatökuvél"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Leitarflýtileiðir"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Minnka tákn"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Stækka tákn"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eða"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Baklýsing lyklaborðs"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Stig %1$d af %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Heimastýringar"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 5494b16..a0d54c267 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Riattiva automaticamente domani"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funzionalità come Quick Share e Trova il mio dispositivo usano il Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Il Bluetooth verrà attivato domani mattina"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Condivisione audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Condivisione audio in corso…"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Batteria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auricolare"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Termico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modalità a una mano"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Apparecchi acustici"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Attivi"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Disconnessi"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Protesi uditive"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Accoppia nuovo dispositivo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic per accoppiare un nuovo dispositivo"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Scorciatoie per la ricerca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona Comprimi"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona Espandi"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oppure"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroilluminazione della tastiera"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Livello %1$d di %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controlli della casa"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 2ad95fb..f773b84 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -278,11 +278,13 @@
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"נשמר"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ניתוק"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"הפעלה"</string>
- <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"החיבור יופעל שוב אוטומטית מחר"</string>
+ <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"יופעל שוב אוטומטית מחר"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"תכונות כמו \'שיתוף מהיר\' ו\'איפה המכשיר שלי\' משתמשות ב-Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"חיבור ה-Bluetooth יופעל מחר בבוקר"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"שיתוף אודיו"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"מתבצע שיתוף של האודיו"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> סוללה"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"אודיו"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"אוזניות"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"תרמי"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"מצב שימוש ביד אחת"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"מכשירי שמיעה"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"פעיל"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"מנותק"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"מכשירי שמיעה"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"התאמה של מכשיר חדש"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"צריך ללחוץ כדי להתאים מכשיר חדש"</string>
@@ -620,7 +620,7 @@
<string name="volume_panel_noise_control_title" msgid="7413949943872304474">"בקרת רעש"</string>
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"אודיו מרחבי"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"השבתה"</string>
- <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"מצב קבוע"</string>
+ <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"מצב סטטי"</string>
<string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"מעקב אחר תנועות הראש"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"יש להקיש כדי לשנות את מצב תוכנת הצלצול"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"השתקה"</string>
@@ -1198,7 +1198,7 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ה-Wi-Fi לא יתחבר באופן אוטומטי בינתיים"</string>
<string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"כדי לעבור בין רשתות, צריך לנתק את האתרנט"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"כדי לשפר את חוויית השימוש במכשיר, אפליקציות ושירותים יוכלו לחפש רשתות Wi-Fi בכל שלב, גם כאשר ה-Wi-Fi כבוי. אפשר לשנות זאת בהגדרות של חיפוש נקודות Wi-Fi. "<annotation id="link">"שינוי"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"כדי לשפר את חוויית השימוש במכשיר, אפליקציות ושירותים יוכלו לחפש רשתות Wi-Fi בכל שלב, גם כאשר ה-Wi-Fi כבוי. אפשר לשנות את זה בהגדרות של חיפוש נקודות Wi-Fi. "<annotation id="link">"שינוי"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"השבתה של מצב טיסה"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"אפליקציית <xliff:g id="APPNAME">%1$s</xliff:g> מבקשת להוסיף להגדרות המהירות את הלחצן הבא"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"להוסיף לחצן"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"קיצורי דרך לחיפוש"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"סמל הכיווץ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"סמל ההרחבה"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"או"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"התאורה האחורית במקלדת"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"רמה %1$d מתוך %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"שליטה במכשירים"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 15c1f8b..6b5d082 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"明日自動的に ON に戻す"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share や「デバイスを探す」などの機能は Bluetooth を使用します"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"明日の朝に Bluetooth が ON になります"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"音声の共有"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"音声を共有中"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"バッテリー <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"オーディオ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ヘッドセット"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"温度"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"片手モード"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"補聴器"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"アクティブ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"未接続"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"補聴器"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"新しいデバイスとペア設定"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"クリックすると、新しいデバイスをペア設定できます"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"検索ショートカット"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"閉じるアイコン"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"開くアイコン"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"または"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"キーボード バックライト"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"レベル %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ホーム コントロール"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 4d17179..399c1f0 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ხელახლა ავტომატურად ჩართვა ხვალ"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ისეთი ფუნქციები, როგორიცაა სწრაფი გაზიარება და ჩემი მოწყობილობის პოვნა, იყენებს Bluetooth-ს"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ჩაირთვება ხვალ დილით"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"აუდიოს გაზიარება"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"აუდიოს გაზიარება"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ბატარეა"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"აუდიო"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ყურსაცვამი"</string>
@@ -366,16 +368,14 @@
<string name="thermal" msgid="6758074791325414831">"თერმული"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ცალი ხელის რეჟიმი"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"სმენის აპარატები"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"აქტიური"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"კავშირი გაწყვეტილია"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"სმენის აპარატები"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ახალი მოწყობილობის დაწყვილება"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"დააწკაპუნეთ ახალი მოწყობილობის დასაწყვილებლად"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"წინასწარ დაყენებული პარამეტრების განახლება ვერ მოხერხდა"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"წინასწარ დაყენებული"</string>
- <string name="live_caption_title" msgid="8916875614623730005">"პირდაპირი სუბტიტრები"</string>
+ <string name="live_caption_title" msgid="8916875614623730005">"ავტოსუბტიტრები"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"გსურთ მოწყობილობის მიკროფონის განბლოკვა?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"გსურთ მოწყობილობის კამერის განბლოკვა?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"გსურთ მოწყობილობის კამერის და მიკროფონის განბლოკვა?"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ძიების მალსახმობები"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ხატულის ჩაკეცვა"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ხატულის გაფართოება"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ან"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"კლავიატურის შენათება"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"დონე: %1$d %2$d-დან"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"სახლის კონტროლი"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 08e9fa2..a3e6179 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Ертең автоматты түрде қосылсын"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share және Find My Device сияқты функциялар Bluetooth-ты пайдаланады."</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ертең таңертең қосылады."</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Аудио бөлісу"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Аудио бөлісу әрекеті орындалып жатыр."</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батарея деңгейі: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Aудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнитура"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Құрылғы қызметінің қандай түріне әсер етті?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Мәселе түрін таңдаңыз."</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Экранды жазу"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Өнімділік режимі"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Пайдаланушы интерфейсі"</string>
+ <string name="thermal" msgid="6758074791325414831">"Термовизия"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Бір қолмен басқару режимі"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Есту құрылғылары"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Қосулы"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Ажыратулы"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Есту құрылғылары"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Жаңа құрылғыны жұптау"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Жаңа құрылғыны жұптау үшін басыңыз."</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"жабық"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ашық"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Стилус батареясы: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Стилусты зарядтағышқа жалғаңыз."</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Стилус батареясының заряды аз"</string>
<string name="video_camera" msgid="7654002575156149298">"Бейнекамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Іздеу жылдам пәрмендері"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жию белгішесі"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жаю белгішесі"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"немесе"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Пернетақта жарығы"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Деңгей: %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Үй басқару элементтері"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index d6538bd..7c6f127 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"បើកដោយស្វ័យប្រវត្តិម្ដងទៀតនៅថ្ងៃស្អែក"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"មុខងារដូចជា Quick Share និង \"រកឧបករណ៍របស់ខ្ញុំ\" ប្រើប៊្លូធូស"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ប៊្លូធូសនឹងបើកនៅព្រឹកស្អែក"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ការស្ដាប់សំឡេងរួមគ្នា"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"កំពុងស្ដាប់សំឡេងរួមគ្នា"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"សំឡេង"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"កាស"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"តើផ្នែកអ្វីនៃបទពិសោធប្រើប្រាស់ឧបករណ៍របស់អ្នកបានរងការប៉ះពាល់?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ជ្រើសរើសប្រភេទបញ្ហា"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ការថតវីដេអូអេក្រង់"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"ប្រតិបត្តិការ"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ផ្ទៃប៉ះ"</string>
+ <string name="thermal" msgid="6758074791325414831">"កម្ដៅ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"មុខងារប្រើដៃម្ខាង"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"សកម្ម"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"បានផ្ដាច់"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ផ្គូផ្គងឧបករណ៍ថ្មី"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ចុច ដើម្បីផ្គូផ្គងឧបករណ៍ថ្មី"</string>
@@ -1201,7 +1198,7 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi នឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិក្នុងពេលនេះទេ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"មើលទាំងអស់"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ដើម្បីប្ដូរបណ្ដាញ សូមផ្ដាច់អ៊ីសឺរណិត"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ដើម្បីធ្វើឱ្យបទពិសោធន៍ប្រើប្រាស់ឧបករណ៍ប្រសើរឡើង កម្មវិធី និងសេវាកម្មនៅតែអាចស្កេនរកបណ្ដាញ Wi‑Fi បានគ្រប់ពេល ទោះបីជានៅពេលដែលបិទ Wi‑Fi ក៏ដោយ។ អ្នកអាចប្ដូរវាបាននៅក្នុងការកំណត់ការស្កេន Wi‑Fi។ "<annotation id="link">"ប្ដូរ"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ដើម្បីធ្វើឱ្យបទពិសោធប្រើប្រាស់ឧបករណ៍ប្រសើរឡើង កម្មវិធី និងសេវាកម្មនៅតែអាចស្កេនរកបណ្ដាញ Wi‑Fi បានគ្រប់ពេល ទោះបីជានៅពេលដែលបិទ Wi‑Fi ក៏ដោយ។ អ្នកអាចប្ដូរវាបាននៅក្នុងការកំណត់ការស្កេន Wi‑Fi។ "<annotation id="link">"ប្ដូរ"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"បិទមុខងារពេលជិះយន្តហោះ"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ចង់បញ្ចូលប្រអប់ខាងក្រោមទៅក្នុងការកំណត់រហ័ស"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"បញ្ចូលប្រអប់"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"បត់"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"លា"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ថ្មប៊ិក <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ភ្ជាប់ប៊ិករបស់អ្នកជាមួយឆ្នាំងសាក"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ថ្មប៊ិកនៅសល់តិច"</string>
<string name="video_camera" msgid="7654002575156149298">"កាមេរ៉ាវីដេអូ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ផ្លូវកាត់ការស្វែងរក"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"រូបតំណាង \"បង្រួម\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"រូបតំណាង \"ពង្រីក\""</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ឬ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ពន្លឺក្រោយក្ដារចុច"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"កម្រិតទី %1$d នៃ %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ការគ្រប់គ្រងផ្ទះ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 92a8b6b..31aa875 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ನಾಳೆ ಪುನಃ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಆನ್ ಮಾಡಿ"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ಕ್ವಿಕ್ ಶೇರ್ ಮತ್ತು Find My Device ನಂತಹ ಫೀಚರ್ಗಳು ಬ್ಲೂಟೂತ್ ಅನ್ನು ಬಳಸುತ್ತವೆ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ಬ್ಲೂಟೂತ್ ನಾಳೆ ಬೆಳಗ್ಗೆ ಆನ್ ಆಗುತ್ತದೆ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ಆಡಿಯೋವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ಬ್ಯಾಟರಿ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ಆಡಿಯೋ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ಹೆಡ್ಸೆಟ್"</string>
@@ -361,24 +363,19 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ಸಾಧನ ಬಳಸುವಾಗ ನೀವು ಯಾವ ರೀತಿಯ ಸಮಸ್ಯೆ ಎದುರಿಸುತ್ತೀರಿ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ಸಮಸ್ಯೆಯ ಪ್ರಕಾರವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡ್"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"ಪರ್ಫಾರ್ಮೆನ್ಸ್"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ಬಳಕೆದಾರ ಇಂಟರ್ಫೇಸ್"</string>
+ <string name="thermal" msgid="6758074791325414831">"ಥರ್ಮಲ್"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ಒಂದು ಕೈ ಮೋಡ್"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ಸಕ್ರಿಯವಾಗಿದೆ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ಡಿಸ್ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ಹೊಸ ಸಾಧನವನ್ನು ಪೇರ್ ಮಾಡಿ"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"ಪ್ರಿಸೆಟ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"ಪ್ರಿಸೆಟ್"</string>
- <string name="live_caption_title" msgid="8916875614623730005">"ಲೈವ್ ಶೀರ್ಷಿಕೆ"</string>
+ <string name="live_caption_title" msgid="8916875614623730005">"ಲೈವ್ ಕ್ಯಾಪ್ಶನ್"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ಸಾಧನದ ಮೈಕ್ರೋಫೋನ್ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ಸಾಧನದ ಕ್ಯಾಮರಾ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ಸಾಧನದ ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ಅನ್ಬ್ಲಾಕ್ ಮಾಡಬೇಕೇ?"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ಅನ್ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ಸ್ಟೈಲಸ್ ಬ್ಯಾಟರಿ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ನಿಮ್ಮ ಸ್ಟೈಲಸ್ ಅನ್ನು ಚಾರ್ಜರ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಿ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ಸ್ಟೈಲಸ್ ಬ್ಯಾಟರಿ ಕಡಿಮೆಯಿದೆ"</string>
<string name="video_camera" msgid="7654002575156149298">"ವೀಡಿಯೊ ಕ್ಯಾಮರಾ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ಹುಡುಕಾಟದ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ಕುಗ್ಗಿಸುವ ಐಕಾನ್"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ವಿಸ್ತೃತಗೊಳಿಸುವ ಐಕಾನ್"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ಅಥವಾ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ಕೀಬೋರ್ಡ್ ಬ್ಯಾಕ್ಲೈಟ್"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ರಲ್ಲಿ %1$d ಮಟ್ಟ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ಮನೆ ನಿಯಂತ್ರಣಗಳು"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index b141b48..91266b7 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"내일 다시 자동으로 사용 설정"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share, 내 기기 찾기 등의 기능에서 블루투스를 사용합니다."</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"블루투스가 내일 아침에 켜집니다."</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"오디오 공유"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"오디오 공유 중"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"오디오"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"헤드셋"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"기기 경험의 어떤 부분에 영향이 있었나요?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"문제 유형 선택"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"화면 녹화"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"성능"</string>
+ <string name="user_interface" msgid="3712869377953950887">"사용자 인터페이스"</string>
+ <string name="thermal" msgid="6758074791325414831">"열화상"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"한 손 사용 모드"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"청각 보조 기기"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"활성"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"연결 끊김"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"청각 보조 기기"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"새 기기와 페어링"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"새 기기와 페어링하려면 클릭하세요"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"접은 상태"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"펼친 상태"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"스타일러스 배터리 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"스타일러스를 충전기에 연결하세요"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"스타일러스 배터리 부족"</string>
<string name="video_camera" msgid="7654002575156149298">"비디오 카메라"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"검색 바로가기"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"접기 아이콘"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"확장 아이콘"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"또는"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"키보드 백라이트"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d단계 중 %1$d단계"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"홈 컨트롤"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index dc7227e..a3fd0a2 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Эртең автоматтык түрдө кайра күйгүзүү"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth Тез бөлүшүү жана Түзмөгүм кайда? сыяктуу функцияларда колдонулат"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth эртең таңда күйөт"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Чогуу угуу"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Чогуу угулууда"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батареянын деңгээли <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнитура"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Түзмөгүңүздүн кайсы бөлүгүнө кедергиси тийди?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Маселенин түрүн тандоо"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Экрандан видео жаздырып алуу"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Иштин майнаптуулугу"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Колдонуучунун интерфейси"</string>
+ <string name="thermal" msgid="6758074791325414831">"Жылуулук"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Бир кол режими"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Угуу аппараттары"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Жигердүү"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Ажыратылды"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Угуу аппараттары"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Жаңы түзмөк кошуу"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Жаңы түзмөк кошуу үчүн басыңыз"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"бүктөлгөн"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ачылган"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Стилустун батареясы: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Стилусту кубаттаңыз"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Стилустун батареясы отурайын деп калды"</string>
<string name="video_camera" msgid="7654002575156149298">"Видео камера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Ыкчам баскычтарды издөө"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жыйыштыруу сүрөтчөсү"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жайып көрсөтүү сүрөтчөсү"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"же"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Баскычтоптун жарыгы"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ичинен %1$d-деңгээл"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Үйдөгү түзмөктөрдү тескөө"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 5894084..31182fd 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ເປີດໃຊ້ໂດຍອັດຕະໂນມັດອີກຄັ້ງມື້ອື່ນ"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ຄຸນສົມບັດຕ່າງໆໃຊ້ Bluetooth ເຊັ່ນ: ການແຊຣ໌ດ່ວນ ແລະ ຊອກຫາອຸປະກອນຂອງຂ້ອຍ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ຈະເປີດມື້ອື່ນເຊົ້າ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ການແບ່ງປັນສຽງ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ກຳລັງແບ່ງປັນສຽງ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ສຽງ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ຊຸດຫູຟັງ"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ສ່ວນໃດຂອງປະສົບການອຸປະກອນຂອງທ່ານໄດ້ຮັບຜົນກະທົບ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ເລືອກປະເພດບັນຫາ"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ບັນທຶກໜ້າຈໍ"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"ປະສິດທິພາບ"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ສ່ວນຕິດຕໍ່ຜູ້ໃຊ້"</string>
+ <string name="thermal" msgid="6758074791325414831">"ຄວາມຮ້ອນ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ໂໝດມືດຽວ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ອຸປະກອນຊ່ວຍຟັງ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ນຳໃຊ້ຢູ່"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ອຸປະກອນຊ່ວຍຟັງ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ຄລິກເພື່ອຈັບຄູ່ອຸປະກອນໃໝ່"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ພັບແລ້ວ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ກາງອອກແລ້ວ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ແບັດເຕີຣີປາກກາ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ເຊື່ອມຕໍ່ປາກກາຂອງທ່ານກັບສາຍສາກ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ແບັດເຕີຣີປາກກາເຫຼືອໜ້ອຍ"</string>
<string name="video_camera" msgid="7654002575156149298">"ກ້ອງວິດີໂອ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ທາງລັດການຊອກຫາ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ໄອຄອນຫຍໍ້ລົງ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ໄອຄອນຂະຫຍາຍ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ຫຼື"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ໄຟປຸ່ມແປ້ນພິມ"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"ລະດັບທີ %1$d ຈາກ %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ການຄວບຄຸມເຮືອນ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 2c9eed8..62c2911 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatiškai vėl įjungti rytoj"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Tokioms funkcijoms kaip „Spartusis bendrinimas“ ir „Rasti įrenginį“ naudojamas „Bluetooth“ ryšys"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"„Bluetooth“ ryšys bus įjungtas rytoj ryte"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Garso įrašų bendrinimas"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Bendrinamas garso įrašas"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akumuliatorius: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Garsas"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Virtualiosios realybės įrenginys"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuri įrenginio funkcija buvo paveikta?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pasirinkite problemos tipą"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekrano įrašas"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Našumas"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Naudotojo sąsaja"</string>
+ <string name="thermal" msgid="6758074791325414831">"Šiluminis"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienos rankos režimas"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Klausos įrenginiai"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktyvus"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Atjungtas"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Klausos įrenginiai"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Susieti naują įrenginį"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Spustelėkite, kad susietumėte naują įrenginį"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sulenkta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"nesulenkta"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Liko rašiklio akumuliatoriaus energijos: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Prijunkite rašiklį prie kroviklio"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Senka rašiklio akumuliatorius"</string>
<string name="video_camera" msgid="7654002575156149298">"Vaizdo kamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Paieškos šaukiniai"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sutraukimo piktograma"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Išskleidimo piktograma"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"arba"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatūros foninis apšvietimas"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d lygis iš %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Namų sistemos valdymas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 6a5d068..8d0b43c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automātiski atkal ieslēgt rīt"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Tādas funkcijas kā “Ātrā kopīgošana” un “Atrast ierīci” izmanto Bluetooth savienojumu"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth savienojums tiks ieslēgts rīt no rīta"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Kopīgot audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Notiek audio kopīgošana"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akumulators: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Austiņas"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuras ierīces funkcijas tika ietekmētas?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Atlasiet problēmas veidu"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekrāna ierakstīšana"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Veiktspēja"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Lietotāja saskarne"</string>
+ <string name="thermal" msgid="6758074791325414831">"Ierīces temperatūra"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienas rokas režīms"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dzirdes aparāti"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktīvs"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Atvienots"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dzirdes aparāti"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Savienot pārī jaunu ierīci"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Noklikšķiniet, lai savienotu pārī jaunu ierīci"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"aizvērta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"atvērta"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Skārienekrāna pildspalvas akumulatora uzlādes līmenis: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Pievienojiet skārienekrāna pildspalvu lādētājam"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Zems skārienekrāna pildspalvas akumulatora līmenis"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Meklēšanas saīsnes"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sakļaušanas ikona"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Izvēršanas ikona"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vai"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastatūras fona apgaismojums"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Līmenis numur %1$d, kopā ir %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Mājas kontrolierīces"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 7c41096..1c889e6 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Автоматски вклучи повторно утре"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Функциите како „Брзо споделување“ и „Најди го мојот уред“ користат Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ќе се вклучи утре наутро"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Споделување аудио"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Се споделува аудио"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батерија: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Слушалки"</string>
@@ -301,7 +303,7 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Корисник"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string>
- <string name="quick_settings_networks_available" msgid="1875138606855420438">"Мрежите се достапни"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Достапни се мрежи"</string>
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Не се достапни мрежи"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Нема достапни Wi-Fi мрежи"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Се вклучува…"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Кој дел од доживувањето на уредот беше засегнат?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изберете тип проблем"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Снимање екран"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Изведба"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Кориснички интерфејс"</string>
+ <string name="thermal" msgid="6758074791325414831">"Термално"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим со една рака"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слушни апарати"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Активно"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Не е поврзано"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слушни апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Спари нов уред"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликнете за да спарите нов уред"</string>
@@ -689,8 +686,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматски"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звук или вибрации"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звук или вибрации и се појавува подолу во делот со разговори"</string>
- <string name="notification_channel_summary_default" msgid="777294388712200605">"Може да ѕвони или вибрира во зависност од поставките за уредот"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Може да ѕвони или вибрира во зависност од поставките на уредот. Стандардно, разговорите од <xliff:g id="APP_NAME">%1$s</xliff:g> се во балончиња."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Може да ѕвони или да вибрира во зависност од поставките за уредот"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Може да ѕвони или да вибрира во зависност од поставките за уредот. Стандардно, разговорите од <xliff:g id="APP_NAME">%1$s</xliff:g> се во балончиња."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Дозволете системот да определи дали известувањево треба да испушти звук или да вибрира"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Статус:</b> поставено на „Стандардно“"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус:</b> намалено на „Тивко“"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{Активна е # апликација}one{Активни се # апликација}other{Активни се # апликации}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Нови информации"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активни апликации"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Овие апликации се активни и работат, дури и кога не ги користите. Ова ја подобрува нивната функционалност, но може да влијае и на траењето на батеријата."</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Овие апликации се активни и работат дури и кога не ги користите. Ова ја подобрува нивната функционалност, но може и да влијае на траењето на батеријата."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Запри"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Запрено"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворен"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворен"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Батерија на пенкало: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Поврзете го пенкалото со полнач"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Слаба батерија на пенкало"</string>
<string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Кратенки за пребарување"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за собирање"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширување"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Осветлување на тастатура"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Ниво %1$d од %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Контроли за домот"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 540358c..3dd91f7 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"നാളെ വീണ്ടും സ്വയമേവ ഓണാക്കുക"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ക്വിക്ക് ഷെയർ, Find My Device പോലുള്ള ഫീച്ചറുകൾ Bluetooth ഉപയോഗിക്കുന്നു"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth നാളെ രാവിലെ ഓണാകും"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ഓഡിയോ പങ്കിടൽ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ഓഡിയോ പങ്കിടുന്നു"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ബാറ്ററി"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ഓഡിയോ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ഹെഡ്സെറ്റ്"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"നിങ്ങളുടെ ഉപകരണ അനുഭവത്തിന്റെ ഏത് ഭാഗമാണ് ബാധിച്ചത്?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"പ്രശ്ന തരം തിരഞ്ഞെടുക്കുക"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"സ്ക്രീൻ റെക്കോർഡ്"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"പ്രകടനം"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ഉപയോക്തൃ ഇന്റർഫേസ്"</string>
+ <string name="thermal" msgid="6758074791325414831">"തെർമൽ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ഒറ്റക്കൈ മോഡ്"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"കേൾവിക്കുള്ള ഉപകരണങ്ങൾ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"സജീവം"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"വിച്ഛേദിച്ചിരിക്കുന്നു"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"കേൾവിക്കുള്ള ഉപകരണങ്ങൾ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"പുതിയ ഉപകരണം ജോടിയാക്കുക"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"പുതിയ ഉപകരണം ജോടിയാക്കാൻ ക്ലിക്ക് ചെയ്യുക"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ഫോൾഡ് ചെയ്തത്"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"അൺഫോൾഡ് ചെയ്തത്"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"സ്റ്റൈലസ് ബാറ്ററി <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"നിങ്ങളുടെ സ്റ്റൈലസ് ചാർജറുമായി കണക്റ്റ് ചെയ്യുക"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"സ്റ്റൈലസിന്റെ ബാറ്ററി ചാർജ് കുറവാണ്"</string>
<string name="video_camera" msgid="7654002575156149298">"വീഡിയോ ക്യാമറ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"തിരയൽ കുറുക്കുവഴികൾ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ചുരുക്കൽ ഐക്കൺ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"വികസിപ്പിക്കൽ ഐക്കൺ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"അല്ലെങ്കിൽ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"കീബോഡ് ബാക്ക്ലൈറ്റ്"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-ൽ %1$d-ാമത്തെ ലെവൽ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ഹോം കൺട്രോളുകൾ"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 47e6936..5539263 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Маргааш автоматаар дахин асаах"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Түргэн хуваалцах, Миний төхөөрөмжийг олох зэрэг онцлогууд Bluetooth-г ашигладаг"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth-г маргааш өглөө асаана"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Аудио хуваалцах"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Аудио хуваалцаж байна"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> батарей"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Чихэвч"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Таны төхөөрөмжийн хэрэглээний аль хэсэгт нөлөөлсөн бэ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Асуудлын төрөл сонгоно уу"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Дэлгэцийн бичлэг"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Гүйцэтгэл"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Хэрэглэгчийн интерфейс"</string>
+ <string name="thermal" msgid="6758074791325414831">"Дулааны"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Нэг гарын горим"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Сонсголын төхөөрөмжүүд"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Идэвхтэй"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Салсан"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Сонсголын төхөөрөмжүүд"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Шинэ төхөөрөмж хослуулах"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Шинэ төхөөрөмж хослуулахын тулд товшино уу"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"эвхсэн"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"дэлгэсэн"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Мэдрэгч үзгийн батарей <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Мэдрэгч үзгээ цэнэглэгчтэй холбоорой"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Мэдрэгч үзэгний батарей бага байна"</string>
<string name="video_camera" msgid="7654002575156149298">"Видео камер"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Товчлолууд хайх"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Хураах дүрс тэмдэг"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Дэлгэх дүрс тэмдэг"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"эсвэл"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Гарын арын гэрэл"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-с %1$d-р түвшин"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Гэрийн удирдлага"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 39f1413..aea4d5a 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"उद्या पुन्हा आपोआप सुरू करा"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"क्विक शेअर आणि Find My Device यांसारखी वैशिष्ट्ये ब्लूटूथ वापरतात"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ब्लूटूथ उद्या सकाळी सुरू होईल"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ऑडिओ शेअरिंग"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ऑडिओ शेअर करत आहे"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> बॅटरी"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ऑडिओ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"थर्मल"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"एकहाती मोड"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"श्रवणयंत्रे"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ॲक्टिव्ह आहे"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"डिस्कनेक्ट केले आहे"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"श्रवणयंत्रे"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नवीन डिव्हाइस पेअर करा"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नवीन डिव्हाइस पेअर करण्यासाठी क्लिक करा"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"शोधण्यासाठी शॉर्टकट"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"कोलॅप्स करा आयकन"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"विस्तार करा आयकन"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"किंवा"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड बॅकलाइट"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d पैकी %1$d पातळी"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 8fce993..0131098 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Dihidupkan lagi esok secara automatik"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Ciri seperti Quick Share dan Find My Device menggunakan Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth akan dihidupkan esok pagi"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Perkongsian Audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Berkongsi Audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> bateri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Set Kepala"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Pengalaman peranti yang manakah yang terjejas?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pilih jenis masalah"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rakam skrin"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Prestasi"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Antara Muka Pengguna"</string>
+ <string name="thermal" msgid="6758074791325414831">"Terma"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mod sebelah tangan"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Peranti pendengaran"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktif"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Diputuskan sambungan"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Peranti pendengaran"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Gandingkan peranti baharu"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menggandingkan peranti baharu"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"terlipat"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tidak terlipat"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateri stilus <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Sambungkan stilus anda kepada pengecas"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateri stilus lemah"</string>
<string name="video_camera" msgid="7654002575156149298">"Kamera video"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan carian"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kuncupkan ikon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kembangkan ikon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Cahaya latar papan kekunci"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Tahap %1$d daripada %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kawalan Rumah"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 9264261..9b19b62 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"မနက်ဖြန် အလိုအလျောက် ပြန်ဖွင့်ရန်"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"‘အမြန် မျှဝေပါ’ နှင့် Find My Device ကဲ့သို့ တူးလ်များသည် ဘလူးတုသ်သုံးသည်"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"မနက်ဖြန်နံနက်တွင် ဘလူးတုသ် ပွင့်ပါမည်"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"အော်ဒီယို မျှဝေခြင်း"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"အော်ဒီယို မျှဝေနေသည်"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ဘက်ထရီ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"အသံ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"မိုက်ခွက်ပါနားကြပ်"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"စက်အသုံးပြုမှု၏ မည်သည့်အပိုင်းကို သက်ရောက်သလဲ။"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ပြဿနာအမျိုးအစား ရွေးရန်"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ဖန်သားပြင်ရိုက်ကူးရန်"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"စွမ်းဆောင်ရည်"</string>
+ <string name="user_interface" msgid="3712869377953950887">"သုံးသူအတွက် ကြားခံစနစ်"</string>
+ <string name="thermal" msgid="6758074791325414831">"အပူဓာတ်"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"လက်တစ်ဖက်သုံးမုဒ်"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"နားကြားကိရိယာ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"သုံးနေသည်"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ချိတ်ဆက်မထားပါ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"နားကြားကိရိယာ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"စက်အသစ်တွဲချိတ်ရန်"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"စက်အသစ် တွဲချိတ်ရန် နှိပ်ပါ"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ခေါက်ထားသည်"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ဖြန့်ထားသည်"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"စတိုင်လပ်စ် ဘက်ထရီ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"စတိုင်လပ်စ်ကို အားသွင်းကိရိယာနှင့် ချိတ်ဆက်ခြင်း"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"စတိုင်လပ်စ် ဘက်ထရီ အားနည်းနေသည်"</string>
<string name="video_camera" msgid="7654002575156149298">"ဗီဒီယိုကင်မရာ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ရှာဖွေစာလုံး ဖြတ်လမ်း"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"လျှော့ပြရန် သင်္ကေတ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ပိုပြရန် သင်္ကေတ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"သို့မဟုတ်"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ကီးဘုတ်နောက်မီး"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"အဆင့် %2$d အနက် %1$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"အိမ်ထိန်းချုပ်မှုများ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 9c2193e..a8befb3 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Slå på igjen i morgen automatisk"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funksjoner som Quick Share og Finn enheten min bruker Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth slås på i morgen tidlig"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Lyddeling"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Deler lyd"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batteri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Hodetelefoner"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvilken del av enhetsopplevelsen din ble påvirket?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Velg problemtype"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skjermopptak"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Ytelse"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Brukergrensesnitt"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termisk"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndsmodus"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Høreapparater"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktiv"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Frakoblet"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Høreapparater"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Koble til en ny enhet"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klikk for å koble til en ny enhet"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"lagt sammen"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"åpen"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batteri i pekepennen: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Koble pekepennen til en lader"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Det er lite batteri i pekepennen"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Snarveier til søk"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Skjul-ikon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vis-ikon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrunnslys for tastatur"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Hjemkontroller"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 94b197b..c26ea3e 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"भोलि फेरि स्वतः अन गर्नुहोस्"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"क्विक सेयर र Find My Device जस्ता सुविधाहरू प्रयोग गर्न ब्लुटुथ चाहिन्छ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ब्लुटुथ भोलि बिहान अन हुने छ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"अडियो सेयरिङ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"अडियो सेयर गरिँदै छ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ब्याट्री"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"अडियो"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"तपाईंको डिभाइसको कुन चाहिँ सुविधा प्रभावित भएको छ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्याको प्रकार चयन गर्नुहोस्"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रिन रेकर्ड"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"पर्फर्मेन्स"</string>
+ <string name="user_interface" msgid="3712869377953950887">"युजर इन्टरफेस"</string>
+ <string name="thermal" msgid="6758074791325414831">"थर्मल"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"एक हाते मोड"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"हियरिङ डिभाइसहरू"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"सक्रिय छ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"डिस्कनेक्ट गरिएको छ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"हियरिङ डिभाइसहरू"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नयाँ डिभाइसमा कनेक्ट गर्न क्लिक गर्नुहोस्"</string>
@@ -382,9 +379,9 @@
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"डिभाइसको माइक्रोफोन अनब्लक गर्ने हो?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"डिभाइसको क्यामेरा अनब्लक गर्ने हो?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"डिभाइसको क्यामेरा र माइक्रोफोन अनब्लक गर्ने हो?"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"यसो गर्नुभयो भने माइक्रोफोन प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाहरूका लागि सो अनुमति अनब्लक गरिन्छ।"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"यसो गर्नुभयो भने क्यामेरा प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाहरूका लागि सो अनुमति अनब्लक गरिन्छ।"</string>
- <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"यसो गर्नुभयो भने क्यामेरा वा माइक्रोफोन प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाहरूका लागि सो अनुमति अनब्लक गरिन्छ।"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"यसो गर्नुभयो भने माइक्रोफोन प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाको हकमा यो अनुमति अनब्लक गरिन्छ।"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"यसो गर्नुभयो भने क्यामेरा प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाको हकमा यो अनुमति अनब्लक गरिन्छ।"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"यसो गर्नुभयो भने क्यामेरा वा माइक्रोफोन प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाको हकमा यो अनुमति अनब्लक गरिन्छ।"</string>
<string name="sensor_privacy_start_use_mic_blocked_dialog_title" msgid="2640140287496469689">"माइक्रोफोन ब्लक गरिएको छ"</string>
<string name="sensor_privacy_start_use_camera_blocked_dialog_title" msgid="7398084286822440384">"क्यामेरा ब्लक गरिएको छ"</string>
<string name="sensor_privacy_start_use_mic_camera_blocked_dialog_title" msgid="195236134743281973">"माइक र क्यामेरा ब्लक गरिएको छ"</string>
@@ -932,7 +929,7 @@
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"कुनै स्वचालित नियम वा एपले बाधा नपुऱ्याउनुहोस् नामक विकल्पलाई सक्रिय गऱ्यो।"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"पृष्ठभूमिमा चल्ने एपहरू"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ब्याट्री र डेटाका प्रयोग सम्बन्धी विवरणहरूका लागि ट्याप गर्नुहोस्"</string>
- <string name="mobile_data_disable_title" msgid="5366476131671617790">"मोबाइल डेटा निष्क्रिय पार्ने हो?"</string>
+ <string name="mobile_data_disable_title" msgid="5366476131671617790">"मोबाइल डेटा अफ गर्ने हो?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"तपाईं <xliff:g id="CARRIER">%s</xliff:g> मार्फत डेटा वा इन्टरनेट प्रयोग गर्न सक्नुहुने छैन। Wi-Fi मार्फत मात्र इन्टरनेट उपलब्ध हुने छ।"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"तपाईंको सेवा प्रदायक"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"फेरि <xliff:g id="CARRIER">%s</xliff:g> को मोबाइल डेटा अन गर्ने हो?"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"फोल्ड गरिएको"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"अनफोल्ड गरिएको"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"स्टाइलसको ब्याट्री <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"आफ्नो स्टाइलस चार्जरमा कनेक्ट गर्नुहोस्"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलसको ब्याट्री लो छ"</string>
<string name="video_camera" msgid="7654002575156149298">"भिडियो क्यामेरा"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"खोजका सर्टकटहरू"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\"कोल्याप्स गर्नुहोस्\" आइकन"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\"एक्स्पान्ड गर्नुहोस्\" आइकन"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"वा"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"किबोर्ड ब्याकलाइट"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d मध्ये %1$d औँ स्तर"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"होम कन्ट्रोलहरू"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8cdbf61..3eba8a8 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Morgen weer automatisch aanzetten"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Functies zoals Quick Share en Vind mijn apparaat gebruiken bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth wordt morgenochtend aangezet"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio delen"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audio delen…"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batterijniveau"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Thermisch"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Bediening met 1 hand"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hoortoestellen"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Actief"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Ontkoppeld"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hoortoestellen"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Nieuw apparaat koppelen"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nieuw apparaat te koppelen"</string>
@@ -1324,10 +1324,9 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Snelkoppelingen voor zoekopdrachten"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icoon voor samenvouwen"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icoon voor uitvouwen"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Achtergrondverlichting van toetsenbord"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d van %2$d"</string>
- <string name="home_controls_dream_label" msgid="6567105701292324257">"Huisbediening"</string>
- <string name="home_controls_dream_description" msgid="4644150952104035789">"Snel toegang tot je huisbediening als screensaver"</string>
+ <string name="home_controls_dream_label" msgid="6567105701292324257">"Bediening voor in huis"</string>
+ <string name="home_controls_dream_description" msgid="4644150952104035789">"Gebruik bediening voor in huis als screensaver"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 287d1a7..1e3ebab 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ଆସନ୍ତାକାଲି ସ୍ୱତଃ ପୁଣି ଚାଲୁ ହେବ"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share ଏବଂ Find My Device ପରି ଫିଚରଗୁଡ଼ିକ ବ୍ଲୁଟୁଥ ବ୍ୟବହାର କରେ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ବ୍ଲୁଟୁଥ ଆସନ୍ତା କାଲି ସକାଳେ ଚାଲୁ ହେବ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ଅଡିଓ ସେୟାରିଂ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ଅଡିଓ ସେୟାର କରାଯାଉଛି"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ବ୍ୟାଟେରୀ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ଅଡିଓ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ହେଡସେଟ୍"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ଆପଣଙ୍କ ଡିଭାଇସ ଅନୁଭୂତିର କେଉଁ ଅଂଶ ପ୍ରଭାବିତ ହୋଇଛି?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ସମସ୍ୟାର ପ୍ରକାର ଚୟନ କରନ୍ତୁ"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ସ୍କ୍ରିନ ରେକର୍ଡ"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"ପରଫରମାନ୍ସ"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ୟୁଜର ଇଣ୍ଟରଫେସ"</string>
+ <string name="thermal" msgid="6758074791325414831">"ଥର୍ମାଲ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ଏକ-ହାତ ମୋଡ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ଶ୍ରବଣ ଡିଭାଇସଗୁଡ଼ିକ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ସକ୍ରିୟ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ଡିସକନେକ୍ଟ ହୋଇଛି"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ଶ୍ରବଣ ଡିଭାଇସଗୁଡ଼ିକ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ନୂଆ ଡିଭାଇସ ପେୟାର କରନ୍ତୁ"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ନୂଆ ଡିଭାଇସ ପେୟାର କରିବାକୁ କ୍ଲିକ କରନ୍ତୁ"</string>
@@ -933,7 +930,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"ବ୍ୟାକଗ୍ରାଉଣ୍ଡରେ ଆପ୍ ଚାଲୁଛି"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ବ୍ୟାଟେରୀ ଏବଂ ଡାଟା ବ୍ୟବହାର ଉପରେ ବିବରଣୀ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ମୋବାଇଲ୍ ଡାଟା ବନ୍ଦ କରିବେ?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"ଡାଟା କିମ୍ବା ଇଣ୍ଟରନେଟ୍କୁ <xliff:g id="CARRIER">%s</xliff:g> ଦ୍ଵାରା ଆପଣଙ୍କର ଆକ୍ସେସ୍ ରହିବ ନାହିଁ। ଇଣ୍ଟରନେଟ୍ କେବଳ ୱାଇ-ଫାଇ ମାଧ୍ୟମରେ ଉପଲବ୍ଧ ହେବ।"</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"ଡାଟା କିମ୍ବା ଇଣ୍ଟର୍ନେଟକୁ <xliff:g id="CARRIER">%s</xliff:g> ଦ୍ଵାରା ଆପଣଙ୍କର ଆକ୍ସେସ ରହିବ ନାହିଁ। ଇଣ୍ଟର୍ନେଟ କେବଳ ୱାଇ-ଫାଇ ମାଧ୍ୟମରେ ଉପଲବ୍ଧ ହେବ।"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ଆପଣଙ୍କ କେରିଅର୍"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"<xliff:g id="CARRIER">%s</xliff:g>କୁ ପୁଣି ସ୍ୱିଚ କରିବେ?"</string>
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"ଉପଲବ୍ଧତା ଆଧାରରେ ମୋବାଇଲ ଡାଟା ସ୍ୱତଃ ସ୍ୱିଚ ହେବ ନାହିଁ"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{#ଟି ଆପ ସକ୍ରିୟ ଅଛି}other{#ଟି ଆପ ସକ୍ରିୟ ଅଛି}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"ନୂଆ ସୂଚନା"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ସକ୍ରିୟ ଆପ୍ସ"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"ଆପଣ ଏହି ଆପ୍ସକୁ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ ସେଗୁଡ଼ିକ ସକ୍ରିୟ ରହିଥାଏ ଏବଂ ଚାଲୁଥାଏ। ଏହା ସେଗୁଡ଼ିକର କାର୍ଯ୍ୟକ୍ଷମତାକୁ ଉନ୍ନତ କରେ, କିନ୍ତୁ ଏହା ମଧ୍ୟ ବ୍ୟାଟେରୀ ଲାଇଫକୁ ପ୍ରଭାବିତ କରିପାରେ।"</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"ଆପଣ ଏହି ଆପ୍ସକୁ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ ସେଗୁଡ଼ିକ ସକ୍ରିୟ ରହିଥାଏ ଏବଂ ଚାଲୁଥାଏ। ଏହା ସେଗୁଡ଼ିକର କାର୍ଯ୍ୟକ୍ଷମତାକୁ ଉନ୍ନତ କରେ, କିନ୍ତୁ ଏହା ମଧ୍ୟ ବେଟେରୀ ଲାଇଫକୁ ପ୍ରଭାବିତ କରିପାରେ।"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ବନ୍ଦ ହୋଇଛି"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ହୋଇଗଲା"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ଫୋଲ୍ଡେଡ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ଅନଫୋଲ୍ଡେଡ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ଷ୍ଟାଇଲସ ବେଟେରୀ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ଏକ ଚାର୍ଜର ସହ ଆପଣଙ୍କ ଷ୍ଟାଇଲସକୁ କନେକ୍ଟ କରନ୍ତୁ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ଷ୍ଟାଇଲସ ବେଟେରୀର ଚାର୍ଜ କମ ଅଛି"</string>
<string name="video_camera" msgid="7654002575156149298">"ଭିଡିଓ କେମେରା"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ସର୍ଚ୍ଚ ସର୍ଟକଟ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ଆଇକନକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ଆଇକନକୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"କିମ୍ବା"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"କୀବୋର୍ଡ ବେକଲାଇଟ"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dରୁ %1$d ନମ୍ବର ଲେଭେଲ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ହୋମ କଣ୍ଟ୍ରୋଲ୍ସ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index a16a8a5..dddda72 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ਕੱਲ੍ਹ ਨੂੰ ਆਪਣੇ ਆਪ ਚਾਲੂ ਹੋ ਜਾਵੇਗਾ"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ਕਵਿੱਕ ਸ਼ੇਅਰ ਅਤੇ Find My Device ਵਰਗੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਬਲੂਟੁੱਥ ਵਰਤਦੀਆਂ ਹਨ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ਬਲੂਟੁੱਥ ਕੱਲ੍ਹ ਸਵੇਰੇ ਚਾਲੂ ਹੋ ਜਾਵੇਗਾ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ਆਡੀਓ ਸਾਂਝਾਕਰਨ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ਆਡੀਓ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ਬੈਟਰੀ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ਆਡੀਓ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ਹੈੱਡਸੈੱਟ"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਕਿਹੜੀ ਸੁਵਿਧਾ ਪ੍ਰਭਾਵਿਤ ਹੋਈ ਸੀ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ਸਮੱਸਿਆ ਦੀ ਕਿਸਮ ਚੁਣੋ"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"ਕਾਰਗੁਜ਼ਾਰੀ"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ਯੂਜ਼ਰ ਇੰਟਰਫ਼ੇਸ"</string>
+ <string name="thermal" msgid="6758074791325414831">"ਥਰਮਲ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ਇੱਕ ਹੱਥ ਮੋਡ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ਕਿਰਿਆਸ਼ੀਲ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ਡਿਸਕਨੈਕਟ ਹੈ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"\'ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ\' \'ਤੇ ਕਲਿੱਕ ਕਰੋ"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ਅਣਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ਸਟਾਈਲਸ ਦੀ ਬੈਟਰੀ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ਆਪਣੇ ਸਟਾਈਲਸ ਨੂੰ ਚਾਰਜਰ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ਸਟਾਈਲਸ ਦੀ ਬੈਟਰੀ ਘੱਟ ਹੈ"</string>
<string name="video_camera" msgid="7654002575156149298">"ਵੀਡੀਓ ਕੈਮਰਾ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ਖੋਜ ਸੰਬੰਧੀ ਸ਼ਾਰਟਕੱਟ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ਪ੍ਰਤੀਕ ਨੂੰ ਸਮੇਟੋ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ਪ੍ਰਤੀਕ ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ਜਾਂ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ਕੀ-ਬੋਰਡ ਬੈਕਲਾਈਟ"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ਵਿੱਚੋਂ %1$d ਪੱਧਰ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ਹੋਮ ਕੰਟਰੋਲ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 58561f1..2dbcf20 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatycznie włącz ponownie jutro"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetootha używają funkcje takie jak szybkie udostępnianie czy Znajdź moje urządzenie"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth włączy się jutro rano"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Udostępnianie dźwięku"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Udostępniam dźwięk"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> naładowania baterii"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Dźwięk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Zestaw słuchawkowy"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Termografia"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Tryb jednej ręki"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Urządzenia słuchowe"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktywny"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Rozłączono"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Urządzenia słuchowe"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sparuj nowe urządzenie"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknij, aby sparować nowe urządzenie"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Skróty do wyszukiwania"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zwijania"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozwijania"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"lub"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podświetlenie klawiatury"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Poziom %1$d z %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Sterowanie domem"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 8f5c519..992db40 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Ativar automaticamente de novo amanhã"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Recursos como o Quick Share e o Encontre Meu Dispositivo usam Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"O Bluetooth será ativado amanhã de manhã"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Compartilhamento de áudio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Compartilhando áudio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Fone de ouvido"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da sua experiência no dispositivo foi afetada?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecionar tipo de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de tela"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Desempenho"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interface do usuário"</string>
+ <string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo uma mão"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparelhos auditivos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ativos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconectados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparelhos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parear novo dispositivo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string>
@@ -639,7 +636,7 @@
<string name="volume_panel_hint_muted" msgid="1124844870181285320">"som desativado"</string>
<string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string>
- <string name="media_output_title_without_playing" msgid="3825663683169305013">"Onde o áudio vai tocar?"</string>
+ <string name="media_output_title_without_playing" msgid="3825663683169305013">"Áudio definido para"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ligando"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string>
<string name="status_bar" msgid="4357390266055077437">"Barra de status"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}many{# de apps estão ativos}other{# apps estão ativos}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nova informação"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também pode afetar a duração da bateria."</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também afeta a duração da bateria."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parado"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluído"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria da stylus em <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecte sua stylus a um carregador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string>
<string name="video_camera" msgid="7654002575156149298">"Filmadora"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Automação residencial"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index df73572..fb0bbfa 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Reativar amanhã automaticamente"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funcionalidades como a Partilha rápida e o serviço Localizar o meu dispositivo usam o Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"O Bluetooth vai ser ativado amanhã de manhã"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Partilha de áudio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"A partilhar áudio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de bateria"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ausc. c/ mic. integ."</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo para uma mão"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ativos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desligados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sincronizar novo dispositivo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para sincronizar um novo dispositivo"</string>
@@ -930,7 +930,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps em execução em segundo plano"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Toque para obter detalhes acerca da utilização da bateria e dos dados"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Desativar os dados móveis?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Não terá acesso a dados ou à Internet através do operador <xliff:g id="CARRIER">%s</xliff:g>. A Internet estará disponível apenas por Wi-Fi."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Não vai ter acesso aos dados nem à Internet através do operador <xliff:g id="CARRIER">%s</xliff:g>. A Internet vai estar disponível só por Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"o seu operador"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"Mudar de novo para <xliff:g id="CARRIER">%s</xliff:g>?"</string>
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"Os dados móveis não vão mudar automaticamente com base na disponibilidade"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone de reduzir"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone de expandir"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz do teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controlos domésticos"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 8f5c519..992db40 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Ativar automaticamente de novo amanhã"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Recursos como o Quick Share e o Encontre Meu Dispositivo usam Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"O Bluetooth será ativado amanhã de manhã"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Compartilhamento de áudio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Compartilhando áudio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Fone de ouvido"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da sua experiência no dispositivo foi afetada?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecionar tipo de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de tela"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Desempenho"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interface do usuário"</string>
+ <string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo uma mão"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparelhos auditivos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ativos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconectados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparelhos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parear novo dispositivo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string>
@@ -639,7 +636,7 @@
<string name="volume_panel_hint_muted" msgid="1124844870181285320">"som desativado"</string>
<string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string>
- <string name="media_output_title_without_playing" msgid="3825663683169305013">"Onde o áudio vai tocar?"</string>
+ <string name="media_output_title_without_playing" msgid="3825663683169305013">"Áudio definido para"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ligando"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string>
<string name="status_bar" msgid="4357390266055077437">"Barra de status"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}many{# de apps estão ativos}other{# apps estão ativos}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nova informação"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também pode afetar a duração da bateria."</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também afeta a duração da bateria."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parado"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluído"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria da stylus em <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecte sua stylus a um carregador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string>
<string name="video_camera" msgid="7654002575156149298">"Filmadora"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Automação residencial"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 366480e..ff07fe9 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Activează din nou automat mâine"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funcții precum Quick Share și Găsește-mi dispozitivul folosesc Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth se va activa mâine dimineață"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Permiterea accesului la audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Se permite accesul la conținutul audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Nivelul bateriei: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Căști"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ce parte a experienței pe dispozitiv a fost afectată?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selectează tipul problemei"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Înregistrarea ecranului"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performanță"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interfața de utilizare"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modul cu o mână"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparate auditive"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Activ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Deconectat"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparate auditive"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Asociază un nou dispozitiv"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Dă clic pentru a asocia un nou dispozitiv"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"închis"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"deschis"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria creionului: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conectează-ți creionul la un încărcător"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Nivelul bateriei creionului este scăzut"</string>
<string name="video_camera" msgid="7654002575156149298">"Cameră video"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Comenzi directe de căutare"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Pictograma de restrângere"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Pictograma de extindere"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"sau"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Iluminarea din spate a tastaturii"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivelul %1$d din %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Comenzi pentru locuință"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index f48e428..1900a8e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Включить завтра автоматически"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth используется в таких функциях и сервисах, как \"Быстрая отправка\" и \"Найти устройство\""</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth включится завтра утром"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Отправка аудио"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Включена отправка аудио"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудиоустройство"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнитура"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"С чем связана проблема, с которой вы столкнулись?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Выберите тип проблемы"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запись экрана"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Производительность"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Интерфейс"</string>
+ <string name="thermal" msgid="6758074791325414831">"Тепловизор"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим управления одной рукой"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слуховые аппараты"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Активно"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Не подключено"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слуховые аппараты"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Подключить новое устройство"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Нажмите, чтобы подключить новое устройство"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"устройство сложено"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"устройство разложено"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Батарея стилуса: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Поставьте стилус на зарядку."</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Низкий заряд батареи стилуса"</string>
<string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Найти быстрые клавиши"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Свернуть\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Развернуть\""</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Подсветка клавиатуры"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Уровень %1$d из %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Управление домом"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 0e621c6..5d41eed 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"හෙට ස්වයංක්රීයව නැවත ක්රියාත්මක කරන්න"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ඉක්මන් බෙදා ගැනීම සහ මගේ උපාංගය සෙවීම වැනි විශේෂාංග බ්ලූටූත් භාවිත කරයි"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"බ්ලූටූත් හෙට උදේ සක්රීය වෙයි"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ශ්රව්ය බෙදා ගැනීම"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ශ්රව්යය බෙදා ගැනීම"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ශ්රව්ය"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"හෙඩ්සෙටය"</string>
@@ -361,24 +363,19 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ඔබේ උපාංග අත්දැකීමේ කුමන කොටසට බලපෑවේ ද?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ගැටලු වර්ගය තෝරන්න"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"තිර පටිගත කිරීම"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"කාර්ය සාධනය"</string>
+ <string name="user_interface" msgid="3712869377953950887">"පරිශීලක අතුරු මුහුණත"</string>
+ <string name="thermal" msgid="6758074791325414831">"තාප"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"තනි අත් ප්රකාරය"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ශ්රවණ උපාංග"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ක්රියාකාරී"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"විසන්ධි විය"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ශ්රවණ උපාංග"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"නව උපාංගය යුගල කරන්න"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"නව උපාංගය යුගල කිරීමට ක්ලික් කරන්න"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"පෙර සැකසීම යාවත්කාලීන කළ නොහැකි විය"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"පෙරසැකසුම"</string>
- <string name="live_caption_title" msgid="8916875614623730005">"සජීවී සිරස්තලය"</string>
+ <string name="live_caption_title" msgid="8916875614623730005">"සජීවී සිරස්තල"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"උපාංග මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"උපාංග කැමරාව අවහිර කිරීම ඉවත් කරන්නද?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"උපාංග කැමරාව සහ මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"නැවූ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"නොනැවූ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"පන්හිඳ බැටරිය <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ඔබේ පන්හිඳ චාජරයකට සම්බන්ධ කරන්න"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"පන්හිඳ බැටරිය අඩුයි"</string>
<string name="video_camera" msgid="7654002575156149298">"වීඩියෝ කැමරාව"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"කෙටි මං සොයන්න"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"හැකුළුම් නිරූපකය"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"දිගහැරීම් නිරූපකය"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"හෝ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"යතුරු පුවරු පසු ආලෝකය"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dන් %1$d වැනි මට්ටම"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"නිවෙස් පාලන"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index ba72fb4..eef2a01 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automaticky zajtra znova zapnúť"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkcie ako Quick Share a Nájdi moje zariadenie používajú Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth sa zapne zajtra ráno"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Zdieľanie zvuku"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Zdieľa sa zvuk"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Batéria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Náhlavná súprava"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Čo v zariadení bolo ovplyvnené?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vyberte typ problému"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rekordér obrazovky"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Výkon"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Používateľské rozhranie"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termálne"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jednej ruky"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Načúvacie zariadenia"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktívne"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Odpojené"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Načúvacie zariadenia"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Spárovať nové zariadenie"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zariadenie"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zložené"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batéria dotykového pera: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Pripojte dotykové pero k nabíjačke"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Stav batérie dotykového pera je nízky"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,10 +1324,9 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Vyhľadávacie odkazy"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zbalenia"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalenia"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"alebo"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvietenie klávesnice"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. úroveň z %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Ovládanie domácnosti"</string>
- <string name="home_controls_dream_description" msgid="4644150952104035789">"Rýchlejšie ovládanie domácnosti v šetriči obrazov."</string>
+ <string name="home_controls_dream_description" msgid="4644150952104035789">"Rýchly prístup k ovládaniu domácnosti z šetriča obrazovky"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index c6c1439..facf72b 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Samodejno znova vklopi jutri"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkcije, kot sta Hitro deljenje in Poišči mojo napravo, uporabljajo Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth se bo vklopil jutri zjutraj"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Deljenje zvoka"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Poteka deljenje zvoka"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvok"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalke z mikrofonom"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na kateri del izkušnje z napravo je to vplivalo?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Izberite vrsto težave"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snemanje zaslona"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Učinkovitost delovanja"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Uporabniški vmesnik"</string>
+ <string name="thermal" msgid="6758074791325414831">"Toplotno"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enoročni način"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni pripomočki"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivno"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Brez povezave"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni pripomočki"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Seznanitev nove naprave"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite za seznanitev nove naprave"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zaprto"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"razprto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Napolnjenost baterije pisala: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Povežite pisalo s polnilnikom."</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Skoraj prazna baterija pisala"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Bližnjice za iskanje"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za strnitev"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za razširitev"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ali"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Osvetlitev tipkovnice"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Stopnja %1$d od %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrolniki za dom"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index dc9407f..5333632 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Aktivizoje automatikisht sërish nesër"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Veçoritë e tilla si \"Ndarja e shpejtë\" dhe \"Gjej pajisjen time\" përdorin Bluetooth-in"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth-i do të aktivizohet nesër në mëngjes"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Ndarja e audios"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audioja po ndahet"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> bateri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Kufje me mikrofon"</string>
@@ -361,12 +363,9 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cila pjesë e përvojës me pajisjen është prekur?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Zgjidh llojin e problemit"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Regjistrim i ekranit"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performanca"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Ndërfaqja e përdoruesit"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termike"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modaliteti i përdorimit me një dorë"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Pajisje ndihmëse për dëgjimin"</string>
<!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
@@ -1275,8 +1274,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"palosur"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"shpalosur"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria e stilolapsit: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Lidhe stilolapsin me një karikues"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria e stilolapsit në nivel të ulët"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1326,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Kërko për shkurtoret"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona e palosjes"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona e zgjerimit"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ose"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Drita e sfondit e tastierës"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveli: %1$d nga %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrollet e shtëpisë"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 1228eef..f35d7d8 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Аутоматски поново укључи сутра"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Функције као што су Quick Share и Пронађи мој уређај користе Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ће се укључити сутра ујутру"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Дељење звука"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Дели се звук"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Ниво батерије је <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Слушалице"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Термална камера"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим једном руком"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слушни апарати"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Активно"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Веза је прекинута"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слушни апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Упари нови уређај"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликните да бисте упарили нов уређај"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пречице претраге"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за скупљање"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширивање"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Позадинско осветљење тастатуре"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. ниво од %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Контроле за дом"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index cf2b93c..535a4aa 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Aktivera automatiskt igen i morgon"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funktioner som Snabbdelning och Hitta min enhet använder Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth aktiveras i morgon bitti"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Ljuddelning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Delar ljud"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batteri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ljud"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Termisk"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhandsläge"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hörhjälpmedel"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktiva"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Frånkopplade"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hörhjälpmedel"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parkoppla en ny enhet"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicka för att parkoppla en ny enhet"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sökgenvägar"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikonen Komprimera"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikonen Utöka"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrundsbelysning för tangentbord"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Hemstyrning"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 1ee1d0c..98a7e03 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Iwashe tena kesho kiotomatiki"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Vipengele kama vile Kutuma Haraka na Tafuta Kifaa Changu hutumia Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth itawaka kesho asubuhi"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Kusikiliza Pamoja"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Mnasikiliza Pamoja"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Chaji ya betri ni <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Sauti"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Vifaa vya sauti"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ni sehemu gani ya matumizi ya kifaa iliathiriwa?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Chagua aina ya tatizo"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rekodi ya skrini"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Utendaji"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Kiolesura"</string>
+ <string name="thermal" msgid="6758074791325414831">"Joto"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Hali ya kutumia kwa mkono mmoja"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Vifaa vya kusikilizia"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Vimeunganishwa"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Havijaunganishwa"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Vifaa vya kusikilizia"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Unganisha kifaa kipya"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Bofya ili uunganishe kifaa kipya"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kimekunjwa"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kimefunguliwa"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Betri ya stylus <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Unganisha stylus yako kwenye chaja"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Chaji ya betri ya Stylus imepungua"</string>
<string name="video_camera" msgid="7654002575156149298">"Kamera ya video"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Njia mkato za kutafutia"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kunja aikoni"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Panua aikoni"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"au"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Mwanga chini ya kibodi"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Kiwango cha %1$d kati ya %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Dhibiti Vifaa Nyumbani"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 6e95c3b..896b55f 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"நாளைக்குத் தானாகவே மீண்டும் இயக்கப்படுதல்"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"விரைவுப் பகிர்தல், Find My Device போன்ற அம்சங்கள் புளூடூத்தைப் பயன்படுத்துகின்றன"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"நாளை காலை புளூடூத் இயக்கப்படும்"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ஆடியோ பகிர்வு"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ஆடியோ பகிரப்படுகிறது"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> பேட்டரி"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ஆடியோ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ஹெட்செட்"</string>
@@ -305,7 +307,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"நெட்வொர்க்குகள் கிடைக்கவில்லை"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"வைஃபை நெட்வொர்க்குகள் இல்லை"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ஆன் செய்கிறது…"</string>
- <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"அலைபரப்பு"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"அனுப்புகிறது"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"பெயரிடப்படாத சாதனம்"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"சாதனங்கள் இல்லை"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"சாதன அனுபவத்தின் எந்தப் பகுதி பாதிக்கப்பட்டது?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"சிக்கல் வகையைத் தேர்வுசெய்க"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ஸ்கிரீன் ரெக்கார்டு"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"செயல்திறன்"</string>
+ <string name="user_interface" msgid="3712869377953950887">"பயனர் இடைமுகம்"</string>
+ <string name="thermal" msgid="6758074791325414831">"தெர்மல்"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ஒற்றைக் கைப் பயன்முறை"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"செவித்துணைக் கருவிகள்"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"செயலில் உள்ளது"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"இணைக்கப்படவில்லை"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"செவித்துணைக் கருவிகள்"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"புதிய சாதனத்தை இணை"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"புதிய சாதனத்தை இணைக்க கிளிக் செய்யலாம்"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"மடக்கப்பட்டது"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"விரிக்கப்பட்டது"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ஸ்டைலஸ் பேட்டரி <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"உங்கள் ஸ்டைலஸைச் சார்ஜருடன் இணையுங்கள்"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ஸ்டைலஸின் பேட்டரி குறைவாக உள்ளது"</string>
<string name="video_camera" msgid="7654002575156149298">"வீடியோ கேமரா"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"தேடல் ஷார்ட்கட்கள்"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"சுருக்குவதற்கான ஐகான்"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"விரிவாக்குவதற்கான ஐகான்"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"அல்லது"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"கீபோர்டு பேக்லைட்"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"நிலை, %2$d இல் %1$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ஹோம் கன்ட்ரோல்கள்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 64d6f9e..b88386f 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"రేపు మళ్లీ ఆటోమేటిక్గా ఆన్ చేస్తుంది"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"క్విక్ షేర్, Find My Device వంటి ఫీచర్లు బ్లూటూత్ను ఉపయోగిస్తాయి"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"బ్లూటూత్ రేపు ఉదయం ఆన్ అవుతుంది"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ఆడియో షేరింగ్"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ఆడియోను షేర్ చేస్తున్నారు"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> బ్యాటరీ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ఆడియో"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"హెడ్సెట్"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"మీ పరికర అనుభవంలో ఏ భాగం ప్రభావితమైంది?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"సమస్య రకాన్ని ఎంచుకోండి"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"స్క్రీన్ రికార్డ్"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"పనితీరు"</string>
+ <string name="user_interface" msgid="3712869377953950887">"యూజర్ ఇంటర్ఫేస్"</string>
+ <string name="thermal" msgid="6758074791325414831">"థర్మల్"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"వన్-హ్యాండెడ్ మోడ్"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"వినికిడి పరికరాలు"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"యాక్టివ్"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"డిస్కనెక్ట్ అయ్యింది"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"వినికిడి పరికరాలు"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"కొత్త పరికరాన్ని పెయిర్ చేయడానికి క్లిక్ చేయండి"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"మడిచే సదుపాయం గల పరికరం"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"మడిచే సదుపాయం లేని పరికరం"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"స్టయిలస్ బ్యాటరీ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"మీ స్టైలస్ను ఛార్జర్కి కనెక్ట్ చేయండి"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"తక్కువ స్టైలస్ బ్యాటరీ"</string>
<string name="video_camera" msgid="7654002575156149298">"వీడియో కెమెరా"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"సెర్చ్ షార్ట్కట్లు"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"కుదించండి చిహ్నం"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"విస్తరించండి చిహ్నం"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"లేదా"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"కీబోర్డ్ బ్యాక్లైట్"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dలో %1$dవ స్థాయి"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"హోమ్ కంట్రోల్స్"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 8a76629..12c676e 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -279,10 +279,12 @@
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ยกเลิกการเชื่อมต่อ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"เปิดใช้งาน"</string>
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"เปิดอีกครั้งโดยอัตโนมัติในวันพรุ่งนี้"</string>
- <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ฟีเจอร์ต่างๆ เช่น Quick Share และหาอุปกรณ์ของฉัน ใช้บลูทูธ"</string>
+ <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ฟีเจอร์ต่างๆ เช่น Quick Share และ \"หาอุปกรณ์ของฉัน\" ใช้บลูทูธ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"บลูทูธจะเปิดพรุ่งนี้เช้า"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"การแชร์เสียง"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"กำลังแชร์เสียง"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"เสียง"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ชุดหูฟัง"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"ความร้อน"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"โหมดมือเดียว"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"เครื่องช่วยฟัง"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ใช้งานอยู่"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ยกเลิกการเชื่อมต่อแล้ว"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"เครื่องช่วยฟัง"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"จับคู่อุปกรณ์ใหม่"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"คลิกเพื่อจับคู่อุปกรณ์ใหม่"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ค้นหาแป้นพิมพ์ลัด"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ไอคอนยุบ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ไอคอนขยาย"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"หรือ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ไฟแบ็กไลต์ของแป้นพิมพ์"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"ระดับที่ %1$d จาก %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ระบบควบคุมอุปกรณ์สมาร์ทโฮม"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index e74139f..84a4541 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Awtomatikong i-on ulit bukas"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Gumagamit ng Bluetooth ang mga feature tulad ng Quick Share at Hanapin ang Aking Device"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Mag-o-on ang Bluetooth bukas ng umaga"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Pag-share ng Audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Ibinabahagi ang Audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> na baterya"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Thermal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-hand mode"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Mga hearing device"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktibo"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Nadiskonekta"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Mga hearing device"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Magpares ng bagong device"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"I-click para magpares ng bagong device"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Mga shortcut ng paghahanap"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"I-collapse ang icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"I-expand ang icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Backlight ng keyboard"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d sa %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Mga Home Control"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index a66fbed..c2df2c2 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Yarın otomatik olarak tekrar aç"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share ve Cihazımı Bul gibi özellikler Bluetooth\'u kullanır"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth yarın sabah açılacak"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Ses Paylaşımı"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Ses paylaşılıyor"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Pil düzeyi <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ses"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Mikrofonlu kulaklık"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cihaz deneyiminiz ne şekilde etkilendi?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sorun türünü seçin"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran kaydedicisi"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performans"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Kullanıcı Arayüzü"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Tek el modu"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"İşitme cihazları"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Etkin"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Bağlı değil"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"İşitme cihazları"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yeni cihaz eşle"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz eşlemek için tıklayın"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"katlanmış"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"katlanmamış"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Ekran kalemi pili: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ekran kaleminizi bir şarj cihazına bağlayın"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Ekran kaleminin pil seviyesi düşük"</string>
<string name="video_camera" msgid="7654002575156149298">"Video kamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Arama kısayolları"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Daralt simgesi"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Genişlet simgesi"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"veya"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klavye aydınlatması"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Seviye %1$d / %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Ev Kontrolleri"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 5262d74..5fcfb3e 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Автоматично ввімкнути знову завтра"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Такі функції, як швидкий обмін і \"Знайти пристрій\", використовують Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth увімкнеться завтра вранці"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Надсилання аудіо"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Надсилання аудіо"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> заряду акумулятора"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудіопристрій"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнітура"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"На який аспект роботи пристрою вплинула проблема?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Виберіть тип проблеми"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запис відео з екрана"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Продуктивність"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Інтерфейс користувача"</string>
+ <string name="thermal" msgid="6758074791325414831">"Нагрівання"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим керування однією рукою"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слухові апарати"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Під’єднано"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Від’єднано"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухові апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Підключити новий пристрій"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Натисніть, щоб підключити новий пристрій"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складений"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"розкладений"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Заряд акумулятора стилуса: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Підключіть стилус до зарядного пристрою"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Низький заряд акумулятора стилуса"</string>
<string name="video_camera" msgid="7654002575156149298">"Відеокамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Комбінації клавіш для пошуку"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок згортання"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок розгортання"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Підсвічування клавіатури"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Рівень %1$d з %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Автоматизація дому"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 0d3f1fe..f08dd7e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -278,11 +278,13 @@
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"محفوظ ہے"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"غیر منسلک کریں"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"فعال کریں"</string>
- <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"کل دوبارہ خودکار طور پر آن ہوگا"</string>
+ <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"کل دوبارہ خودکار طور پر آن کریں"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"فوری اشتراک اور \'میرا آلہ ڈھونڈیں\' جیسی خصوصیات بلوٹوتھ کا استعمال کرتی ہیں"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"بلوٹوتھ کل صبح آن ہو جائے گا"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"آڈیو کا اشتراک"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"آڈیو کا اشتراک ہو رہا ہے"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> بیٹری"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"آڈیو"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ہیڈ سیٹ"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"تھرمل"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ایک ہاتھ کی وضع"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سماعت کے آلات"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"فعال"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"غیر منسلک ہے"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سماعت کے آلات"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"نئے آلے کا جوڑا بنائیں"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"نئے آلے کا جوڑا بنانے کے لیے کلک کریں"</string>
@@ -1328,8 +1328,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"تلاش کے شارٹ کٹس"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"آئیکن سکیڑیں"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"آئیکن پھیلائیں"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"کی بورڈ بیک لائٹ"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d میں سے %1$d کا لیول"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ہوم کنٹرولز"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 3f3983d..4a04a33 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Ertaga yana avtomatik yoqilsin"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Tezkor ulashuv va Qurilmamni top kabi funksiyalar Bluetooth ishlatadi"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ertaga ertalab yoqiladi"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio ulashuvi"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audio ulashuvi yoniq"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Garnitura"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Termal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Ixcham rejim"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Eshitish qurilmalari"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Faol"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Uzildi"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Eshitish qurilmalari"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yangi qurilmani ulash"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yangi qurilmani ulash uchun bosing"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tezkor tugmalar qidiruvi"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Yigʻish belgisi"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Yoyish belgisi"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"yoki"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura orqa yoritkichi"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Daraja: %1$d / %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Uy boshqaruvi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index dc4fa12..45d9165 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Tự động bật lại vào ngày mai"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Các tính năng như Chia sẻ nhanh và Tìm thiết bị của tôi đều sử dụng Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth sẽ bật vào sáng mai"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Chia sẻ âm thanh"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Đang chia sẻ âm thanh"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> pin"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Âm thanh"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Tai nghe"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Bạn gặp loại vấn đề gì khi dùng thiết bị?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Chọn loại vấn đề"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ghi màn hình"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Hiệu suất"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Giao diện người dùng"</string>
+ <string name="thermal" msgid="6758074791325414831">"Nhiệt"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Chế độ một tay"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Thiết bị trợ thính"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Đang hoạt động"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Đã ngắt kết nối"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Thiết bị trợ thính"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Ghép nối thiết bị mới"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Nhấp để ghép nối thiết bị mới"</string>
@@ -933,7 +930,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"Ứng dụng đang chạy trong nền"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Nhấn để biết chi tiết về mức sử dụng dữ liệu và pin"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Tắt dữ liệu di động?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Bạn sẽ không có quyền sử dụng dữ liệu hoặc truy cập Internet thông qua chế độ <xliff:g id="CARRIER">%s</xliff:g>. Bạn chỉ có thể truy cập Internet thông qua Wi-Fi."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Bạn sẽ không có quyền sử dụng dữ liệu hoặc truy cập Internet thông qua mạng <xliff:g id="CARRIER">%s</xliff:g>. Bạn chỉ có thể truy cập Internet thông qua Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"nhà mạng của bạn"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"Chuyển về <xliff:g id="CARRIER">%s</xliff:g>?"</string>
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"Dữ liệu di động sẽ không tự động chuyển dựa trên tình trạng phủ sóng"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gập"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"mở"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Mức pin bút cảm ứng <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Hãy kết nối bút cảm ứng với bộ sạc"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bút cảm ứng bị yếu pin"</string>
<string name="video_camera" msgid="7654002575156149298">"Máy quay video"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Lối tắt tìm kiếm"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Biểu tượng Thu gọn"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Biểu tượng Mở rộng"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"hoặc"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Đèn nền bàn phím"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Độ sáng %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Điều khiển nhà"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 9b69f9e..98a1187 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"明天自动重新开启"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"快速分享、查找我的设备等功能会使用蓝牙"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"蓝牙将在明天早上开启"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"音频分享"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"正在分享音频"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> 的电量"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音频"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳机"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"设备体验的哪个方面受到影响?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"选择问题类型"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"屏幕录制"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"性能"</string>
+ <string name="user_interface" msgid="3712869377953950887">"界面"</string>
+ <string name="thermal" msgid="6758074791325414831">"散热"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"单手模式"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助听装置"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"已连接"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"已断开连接"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助听装置"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"与新设备配对"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"点击即可与新设备配对"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"折叠状态"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"展开状态"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"触控笔电量为 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"请将触控笔连接充电器"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"触控笔电池电量低"</string>
<string name="video_camera" msgid="7654002575156149298">"摄像机"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜索快捷键"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收起图标"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展开图标"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"键盘背光"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 级,共 %2$d 级"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"家居控制"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 5c164ab..edc624f 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"明天自動重新開啟"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"「快速共享」和「尋找我的裝置」等功能都會使用藍牙"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"藍牙將於明天上午開啟"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"音訊分享功能"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"正在分享音訊"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音訊"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳機"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"哪些裝置使用體驗受影響?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"選取問題類型"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"螢幕錄影"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"效能"</string>
+ <string name="user_interface" msgid="3712869377953950887">"使用者介面"</string>
+ <string name="thermal" msgid="6758074791325414831">"熱能"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"單手模式"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助聽器"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"已連線"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"已中斷連線"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助聽器"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"配對新裝置"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"㩒一下就可以配對新裝置"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已打開"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"觸控筆電量:<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"將觸控筆連接充電器"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"觸控筆電量不足"</string>
<string name="video_camera" msgid="7654002575156149298">"攝影機"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"鍵盤背光"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 級,共 %2$d 級"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"智能家居"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 0d50ad5..5679282 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"明天自動重新開啟"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"「快速分享」和「尋找我的裝置」等功能都需要使用藍牙技術"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"藍牙會在明天早上開啟"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"音訊分享"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"正在分享音訊"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音訊"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳機"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"哪些裝置使用體驗受到影響?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"選取問題類型"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"螢幕錄影"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"效能"</string>
+ <string name="user_interface" msgid="3712869377953950887">"使用者介面"</string>
+ <string name="thermal" msgid="6758074791325414831">"熱成像"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"單手模式"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助聽器"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"已連線"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"連線中斷"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助聽器"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"配對新裝置"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"按一下即可配對新裝置"</string>
@@ -380,7 +377,7 @@
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"預設"</string>
<string name="live_caption_title" msgid="8916875614623730005">"即時字幕"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解除封鎖裝置麥克風嗎?"</string>
- <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解除封鎖裝置相機嗎?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"解除封鎖裝置相機?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要將裝置的相機和麥克風解除封鎖嗎?"</string>
<string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"執行後,具備麥克風存取權的所有應用程式和服務,都將可使用麥克風。"</string>
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"執行後,具備相機存取權的所有應用程式和服務,都將可使用相機。"</string>
@@ -933,7 +930,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"在背景執行的應用程式"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"輕觸即可查看電池和數據用量詳情"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"要關閉行動數據嗎?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"你將無法透過「<xliff:g id="CARRIER">%s</xliff:g>」使用行動數據或網際網路。你只能透過 Wi-Fi 使用網際網路。"</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"你將無法透過「<xliff:g id="CARRIER">%s</xliff:g>」使用行動數據或網際網路,只能利用 Wi-Fi 上網。"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"你的電信業者"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"要切換回「<xliff:g id="CARRIER">%s</xliff:g>」嗎?"</string>
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"行動數據不會依據可用性自動切換"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# 個應用程式正在運作}other{# 個應用程式正在運作}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"新資訊"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"運作中的應用程式"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"這些應用程式會在沒有使用的情況下持續運作。應用程式的實用度會因此提升,但也可能影響電池續航力。"</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"這些應用程式即使是在閒置狀態下,也會持續運作。應用程式的功能會因而提升,但也可能影響電池續航力。"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"已停止"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"完成"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已展開"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"觸控筆電量:<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"將觸控筆接上充電器"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"觸控筆電力不足"</string>
<string name="video_camera" msgid="7654002575156149298">"攝影機"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"鍵盤背光"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 級,共 %2$d 級"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"居家控制"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 2e03bd5..a0a57ac 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Vula ngokuzenzekela futhi kusasa"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Izakhi ezifana nokuthi Ukwabelana Ngokushesha kanye nokuthi Thola Idivayisi Yami zisebenzisa i-Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"IBluetooth izovuleka kusasa ekuseni"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Ukwabelana Ngokuqoshiwe"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Ukwabelana Ngomsindo"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ibhethri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Umsindo"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ihedisethi"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuthinteke yiphi ingxenye yokusebenzisa idivayisi?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Khetha uhlobo lwenkinga"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Irekhodi lesikrini"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Ukusebenza"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Okusetshenziswa Kubonwa"</string>
+ <string name="thermal" msgid="6758074791325414831">"Ithermal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Imodi yesandla esisodwa"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Izinsizakuzwa"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Kuyasebenza"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Inqamukile"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Izinsizakuzwa"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Bhangqa idivayisi entsha"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Chofoza ukuze ubhangqe idivayisi entsha"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kugoqiwe"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kuvuliwe"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Ibhethri lestylus <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Xhuma i-stylus yakho kushaja"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Ibhethri le-stylus liphansi"</string>
<string name="video_camera" msgid="7654002575156149298">"Ikhamera yevidiyo"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sesha izinqamuleli"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Goqa isithonjana"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Nweba isithonjana"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"noma"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Ilambu lekhibhodi"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Ileveli %1$d ka-%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Izilawuli Zasekhaya"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d979abb..e825fc5 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1122,6 +1122,8 @@
<dimen name="biometric_prompt_panel_max_width">640dp</dimen>
<dimen name="biometric_prompt_land_small_horizontal_guideline_padding">344dp</dimen>
<dimen name="biometric_prompt_two_pane_udfps_horizontal_guideline_padding">114dp</dimen>
+ <dimen name="biometric_prompt_two_pane_udfps_shorter_content_width">216dp</dimen>
+ <dimen name="biometric_prompt_two_pane_udfps_shorter_horizontal_guideline_padding">661dp</dimen>
<dimen name="biometric_prompt_two_pane_medium_horizontal_guideline_padding">640dp</dimen>
<dimen name="biometric_prompt_one_pane_medium_top_guideline_padding">119dp</dimen>
<dimen name="biometric_prompt_one_pane_medium_horizontal_guideline_padding">0dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0017db6..fe968a7 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -319,6 +319,29 @@
<string name="screenrecord_save_error">Error saving screen recording</string>
<!-- A toast message shown when the screen recording cannot be started due to a generic error [CHAR LIMIT=NONE] -->
<string name="screenrecord_start_error">Error starting screen recording</string>
+ <!-- Title for a dialog shown to the user that will let them stop recording their screen [CHAR LIMIT=50] -->
+ <string name="screenrecord_stop_dialog_title">Stop recording screen?</string>
+ <!-- Text telling a user that they will stop recording their screen if they click the "Stop recording" button [CHAR LIMIT=100] -->
+ <string name="screenrecord_stop_dialog_message">You will stop recording your screen</string>
+ <!-- Button to stop a screen recording [CHAR LIMIT=35] -->
+ <string name="screenrecord_stop_dialog_button">Stop recording</string>
+
+ <!-- Title for a dialog shown to the user that will let them stop sharing their screen to another app on the device [CHAR LIMIT=50] -->
+ <string name="share_to_app_stop_dialog_title">Stop sharing screen?</string>
+ <!-- Text telling a user that they will stop sharing their screen if they click the "Stop sharing" button [CHAR LIMIT=100] -->
+ <string name="share_to_app_stop_dialog_message">You will stop sharing your screen</string>
+ <!-- Button to stop screen sharing [CHAR LIMIT=35] -->
+ <string name="share_to_app_stop_dialog_button">Stop sharing</string>
+
+ <!-- Title for a dialog shown to the user that will let them stop casting their screen to a different device [CHAR LIMIT=50] -->
+ <string name="cast_to_other_device_stop_dialog_title">Stop casting screen?</string>
+ <!-- Text telling a user that they will stop casting their screen to a different device if they click the "Stop casting" button [CHAR LIMIT=100] -->
+ <string name="cast_to_other_device_stop_dialog_message">You will stop casting your screen</string>
+ <!-- Button to stop screen casting to a different device [CHAR LIMIT=35] -->
+ <string name="cast_to_other_device_stop_dialog_button">Stop casting</string>
+
+ <!-- Button to close a dialog without doing any action [CHAR LIMIT=20] -->
+ <string name="close_dialog_button">Close</string>
<!-- Notification title displayed for issue recording [CHAR LIMIT=50]-->
<string name="issuerecord_title">Issue Recorder</string>
@@ -3538,6 +3561,15 @@
-->
<string name="shortcut_helper_key_combinations_or_separator">or</string>
+ <!-- Label for button opening tutorial for back gesture on touchpad [CHAR LIMIT=NONE] -->
+ <string name="touchpad_tutorial_back_gesture_button">Back gesture</string>
+ <!-- Label for button opening tutorial for back gesture on touchpad [CHAR LIMIT=NONE] -->
+ <string name="touchpad_tutorial_home_gesture_button">Home gesture</string>
+ <!-- Label for button opening tutorial on using Action key from keyboard [CHAR LIMIT=NONE] -->
+ <string name="touchpad_tutorial_action_key_button">Action key</string>
+ <!-- Label for button finishing touchpad tutorial [CHAR LIMIT=NONE] -->
+ <string name="touchpad_tutorial_done_button">Done</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] -->
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index b4d53d0..a87ee24 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -364,7 +364,7 @@
if (midGuideline != null) {
val left =
if (bounds.left >= 0) {
- bounds.left
+ abs(bounds.left)
} else {
view.width - abs(bounds.left)
}
@@ -372,7 +372,7 @@
if (bounds.right >= 0) {
view.width - abs(bounds.right)
} else {
- bounds.right
+ abs(bounds.right)
}
val mid = (left + right) / 2
mediumConstraintSet.setGuidelineBegin(midGuideline.id, mid)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 68a3f5d..7d494a5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -30,6 +30,7 @@
import android.hardware.biometrics.Flags.customBiometricPrompt
import android.hardware.biometrics.PromptContentView
import android.os.UserHandle
+import android.text.TextPaint
import android.util.Log
import android.util.RotationUtils
import android.view.HapticFeedbackConstants
@@ -52,6 +53,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus
import com.android.systemui.res.R
+import com.android.systemui.util.kotlin.combine
import javax.inject.Inject
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
@@ -260,15 +262,15 @@
val position: Flow<PromptPosition> =
combine(
_forceLargeSize,
+ promptKind,
displayStateInteractor.isLargeScreen,
displayStateInteractor.currentRotation,
modalities
- ) { forceLarge, isLargeScreen, rotation, modalities ->
+ ) { forceLarge, promptKind, isLargeScreen, rotation, modalities ->
when {
forceLarge ||
isLargeScreen ||
- promptKind.value.isOnePaneNoSensorLandscapeBiometric() ->
- PromptPosition.Bottom
+ promptKind.isOnePaneNoSensorLandscapeBiometric() -> PromptPosition.Bottom
rotation == DisplayRotation.ROTATION_90 -> PromptPosition.Right
rotation == DisplayRotation.ROTATION_270 -> PromptPosition.Left
rotation == DisplayRotation.ROTATION_180 && modalities.hasUdfps ->
@@ -308,6 +310,10 @@
context.resources.getDimensionPixelSize(
R.dimen.biometric_prompt_two_pane_udfps_horizontal_guideline_padding
)
+ private val udfpsHorizontalShorterGuidelinePadding =
+ context.resources.getDimensionPixelSize(
+ R.dimen.biometric_prompt_two_pane_udfps_shorter_horizontal_guideline_padding
+ )
private val mediumTopGuidelinePadding =
context.resources.getDimensionPixelSize(
R.dimen.biometric_prompt_one_pane_medium_top_guideline_padding
@@ -449,47 +455,6 @@
}
}
- /**
- * Rect for positioning prompt guidelines (left, top, right, unused)
- *
- * Negative values are used to signify that guideline measuring should be flipped, measuring
- * from opposite side of the screen
- */
- val guidelineBounds: Flow<Rect> =
- combine(iconPosition, promptKind, size, position, modalities) {
- _,
- promptKind,
- size,
- position,
- modalities ->
- when (position) {
- PromptPosition.Bottom ->
- if (promptKind.isOnePaneNoSensorLandscapeBiometric()) {
- Rect(0, 0, 0, 0)
- } else {
- Rect(0, mediumTopGuidelinePadding, 0, 0)
- }
- PromptPosition.Right ->
- if (size.isSmall) {
- Rect(-smallHorizontalGuidelinePadding, 0, 0, 0)
- } else if (modalities.hasUdfps) {
- Rect(udfpsHorizontalGuidelinePadding, 0, 0, 0)
- } else {
- Rect(-mediumHorizontalGuidelinePadding, 0, 0, 0)
- }
- PromptPosition.Left ->
- if (size.isSmall) {
- Rect(0, 0, -smallHorizontalGuidelinePadding, 0)
- } else if (modalities.hasUdfps) {
- Rect(0, 0, udfpsHorizontalGuidelinePadding, 0)
- } else {
- Rect(0, 0, -mediumHorizontalGuidelinePadding, 0)
- }
- PromptPosition.Top -> Rect()
- }
- }
- .distinctUntilChanged()
-
/** Padding for prompt UI elements */
val promptPadding: Flow<Rect> =
combine(size, displayStateInteractor.currentRotation) { size, rotation ->
@@ -556,6 +521,81 @@
if (contentView == null) description else ""
}
+ private val hasOnlyOneLineTitle: Flow<Boolean> =
+ combine(title, subtitle, contentView, description) {
+ title,
+ subtitle,
+ contentView,
+ description ->
+ if (subtitle.isNotEmpty() || contentView != null || description.isNotEmpty()) {
+ false
+ } else {
+ val maxWidth =
+ context.resources.getDimensionPixelSize(
+ R.dimen.biometric_prompt_two_pane_udfps_shorter_content_width
+ )
+ val attributes =
+ context.obtainStyledAttributes(
+ R.style.TextAppearance_AuthCredential_Title,
+ intArrayOf(android.R.attr.textSize)
+ )
+ val paint = TextPaint()
+ paint.textSize = attributes.getDimensionPixelSize(0, 0).toFloat()
+ val textWidth = paint.measureText(title)
+ attributes.recycle()
+ textWidth / maxWidth <= 1
+ }
+ }
+
+ /**
+ * Rect for positioning prompt guidelines (left, top, right, unused)
+ *
+ * Negative values are used to signify that guideline measuring should be flipped, measuring
+ * from opposite side of the screen
+ */
+ val guidelineBounds: Flow<Rect> =
+ combine(iconPosition, promptKind, size, position, modalities, hasOnlyOneLineTitle) {
+ _,
+ promptKind,
+ size,
+ position,
+ modalities,
+ hasOnlyOneLineTitle ->
+ var left = 0
+ var top = 0
+ var right = 0
+ when (position) {
+ PromptPosition.Bottom -> {
+ val noSensorLandscape = promptKind.isOnePaneNoSensorLandscapeBiometric()
+ top = if (noSensorLandscape) 0 else mediumTopGuidelinePadding
+ }
+ PromptPosition.Right ->
+ left = getHorizontalPadding(size, modalities, hasOnlyOneLineTitle)
+ PromptPosition.Left ->
+ right = getHorizontalPadding(size, modalities, hasOnlyOneLineTitle)
+ PromptPosition.Top -> {}
+ }
+ Rect(left, top, right, 0)
+ }
+ .distinctUntilChanged()
+
+ private fun getHorizontalPadding(
+ size: PromptSize,
+ modalities: BiometricModalities,
+ hasOnlyOneLineTitle: Boolean
+ ) =
+ if (size.isSmall) {
+ -smallHorizontalGuidelinePadding
+ } else if (modalities.hasUdfps) {
+ if (hasOnlyOneLineTitle) {
+ -udfpsHorizontalShorterGuidelinePadding
+ } else {
+ udfpsHorizontalGuidelinePadding
+ }
+ } else {
+ -mediumHorizontalGuidelinePadding
+ }
+
/** If the indicator (help, error) message should be shown. */
val isIndicatorMessageVisible: Flow<Boolean> =
combine(
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index d522c7e..88c3f9f6 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -208,7 +208,10 @@
// doing any translation.
CommunalScenes.Communal
}
- to == KeyguardState.GONE -> CommunalScenes.Blank
+ // Transitioning to Blank scene when entering the edit mode will be handled separately
+ // with custom animations.
+ to == KeyguardState.GONE && !communalInteractor.editModeOpen.value ->
+ CommunalScenes.Blank
!docked && !KeyguardState.deviceIsAwakeInState(to) -> {
// If the user taps the screen and wakes the device within this timeout, we don't
// want to dismiss the hub
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 3e513f8..00678a8 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
@@ -38,6 +38,7 @@
import com.android.systemui.communal.shared.model.CommunalContentSize.THIRD
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
+import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.communal.widgets.CommunalAppWidgetHost
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
import com.android.systemui.communal.widgets.WidgetConfigurator
@@ -307,6 +308,7 @@
preselectedKey: String? = null,
shouldOpenWidgetPickerOnStart: Boolean = false,
) {
+ communalSceneInteractor.setEditModeState(EditModeState.STARTING)
editWidgetsActivityStarter.startActivity(preselectedKey, shouldOpenWidgetPickerOnStart)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
index 0dab67c..20d8a2a 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
@@ -22,14 +22,17 @@
import com.android.systemui.communal.data.repository.CommunalSceneRepository
import com.android.systemui.communal.domain.model.CommunalTransitionProgressModel
import com.android.systemui.communal.shared.model.CommunalScenes
+import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
@@ -57,11 +60,32 @@
communalSceneRepository.snapToScene(newScene, delayMillis)
}
+ /** Immediately snaps to the new scene when activity is started. */
+ fun snapToSceneForActivityStart(newScene: SceneKey, delayMillis: Long = 0) {
+ // skip if we're starting edit mode activity, as it will be handled later by changeScene
+ // with transition key [CommunalTransitionKeys.ToEditMode].
+ if (_editModeState.value == EditModeState.STARTING) {
+ return
+ }
+ snapToScene(newScene, delayMillis)
+ }
+
/**
* Target scene as requested by the underlying [SceneTransitionLayout] or through [changeScene].
*/
val currentScene: Flow<SceneKey> = communalSceneRepository.currentScene
+ private val _editModeState = MutableStateFlow<EditModeState?>(null)
+ /**
+ * Current state for glanceable hub edit mode, used to chain the animations when transitioning
+ * between communal scene and the edit mode activity.
+ */
+ val editModeState = _editModeState.asStateFlow()
+
+ fun setEditModeState(value: EditModeState?) {
+ _editModeState.value = value
+ }
+
/** Transition state of the hub mode. */
val transitionState: StateFlow<ObservableTransitionState> =
communalSceneRepository.transitionState
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
index 73cfb52..11fb233 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt
@@ -26,6 +26,10 @@
object CommunalTransitionKeys {
/** Fades the glanceable hub without any translation */
val SimpleFade = TransitionKey("SimpleFade")
+ /** Transition from the glanceable hub before entering edit mode */
+ val ToEditMode = TransitionKey("ToEditMode")
+ /** Transition to the glanceable hub after exiting edit mode */
+ val FromEditMode = TransitionKey("FromEditMode")
/** Immediately transitions without any delay */
val Immediately = TransitionKey("Immediately")
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/EditModeState.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/EditModeState.kt
new file mode 100644
index 0000000..ace9c2e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/EditModeState.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.shared.model
+
+/**
+ * Models the state of the edit mode activity. Used to chain the animation during the transition
+ * between the hub on communal scene, and the edit mode activity after unlocking the keyguard.
+ */
+enum class EditModeState(val value: Int) {
+ // starting activity after dismissing keyguard
+ STARTING(0),
+ // activity content is showing
+ SHOWING(1),
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 8cd5603..cc90730 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -25,6 +25,7 @@
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.model.CommunalContentModel
+import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.media.controls.ui.view.MediaHost
import kotlinx.coroutines.flow.Flow
@@ -34,12 +35,15 @@
/** The base view model for the communal hub. */
abstract class BaseCommunalViewModel(
- private val communalSceneInteractor: CommunalSceneInteractor,
+ val communalSceneInteractor: CommunalSceneInteractor,
private val communalInteractor: CommunalInteractor,
val mediaHost: MediaHost,
) {
val currentScene: Flow<SceneKey> = communalSceneInteractor.currentScene
+ /** Used to animate showing or hiding the communal content. */
+ open val isCommunalContentVisible: Flow<Boolean> = MutableStateFlow(false)
+
/** Whether communal hub should be focused by accessibility tools. */
open val isFocusable: Flow<Boolean> = MutableStateFlow(false)
@@ -63,6 +67,8 @@
communalSceneInteractor.changeScene(scene, transitionKey)
}
+ fun setEditModeState(state: EditModeState?) = communalSceneInteractor.setEditModeState(state)
+
/**
* Updates the transition state of the hub [SceneTransitionLayout].
*
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index 5312aec..c0c5861 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -30,21 +30,27 @@
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.log.CommunalUiEvent
+import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.dagger.MediaModule
import com.android.systemui.res.R
+import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import javax.inject.Inject
import javax.inject.Named
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
@@ -56,6 +62,7 @@
communalSceneInteractor: CommunalSceneInteractor,
private val communalInteractor: CommunalInteractor,
private val communalSettingsInteractor: CommunalSettingsInteractor,
+ keyguardTransitionInteractor: KeyguardTransitionInteractor,
@Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
private val uiEventLogger: UiEventLogger,
@CommunalLog logBuffer: LogBuffer,
@@ -66,6 +73,20 @@
override val isEditMode = true
+ override val isCommunalContentVisible: Flow<Boolean> =
+ communalSceneInteractor.editModeState.map { it == EditModeState.SHOWING }
+
+ /**
+ * Emits when edit mode activity can show, after we've transitioned to [KeyguardState.GONE]
+ * and edit mode is open.
+ */
+ val canShowEditMode =
+ allOf(
+ keyguardTransitionInteractor.isFinishedInState(KeyguardState.GONE),
+ communalInteractor.editModeOpen
+ )
+ .filter { it }
+
// Only widgets are editable.
override val communalContent: Flow<List<CommunalContentModel>> =
communalInteractor.widgetContent.onEach { models ->
@@ -172,6 +193,11 @@
/** Sets whether edit mode is currently open */
fun setEditModeOpen(isOpen: Boolean) = communalInteractor.setEditModeOpen(isOpen)
+ /** Called when exiting the edit mode, before transitioning back to the communal scene. */
+ fun cleanupEditModeState() {
+ communalSceneInteractor.setEditModeState(null)
+ }
+
companion object {
private const val TAG = "CommunalEditModeViewModel"
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 c6fa5a84..11247df 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
@@ -125,6 +125,8 @@
logger.d({ "Content updated: $str1" }) { str1 = models.joinToString { it.key } }
}
+ override val isCommunalContentVisible: Flow<Boolean> = MutableStateFlow(true)
+
/**
* Freeze the content flow, when an activity is about to show, like starting a timer via voice:
* 1) in handheld mode, use the keyguard occluded state;
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index 50477b1..40df6cec 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -37,6 +37,7 @@
import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
+import com.android.systemui.communal.shared.model.EditModeState
import com.android.systemui.communal.ui.compose.CommunalHub
import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
import com.android.systemui.communal.util.WidgetPickerIntentUtils.getWidgetExtraFromIntent
@@ -107,6 +108,7 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ listenForTransitionAndChangeScene()
communalViewModel.setEditModeOpen(true)
@@ -138,6 +140,22 @@
}
}
+ // Handle scene change to show the activity and animate in its content
+ private fun listenForTransitionAndChangeScene() {
+ lifecycleScope.launch {
+ communalViewModel.canShowEditMode.collect {
+ communalViewModel.changeScene(
+ CommunalScenes.Blank,
+ CommunalTransitionKeys.ToEditMode
+ )
+ // wait till transitioned to Blank scene, then animate in communal content in
+ // edit mode
+ communalViewModel.currentScene.first { it == CommunalScenes.Blank }
+ communalViewModel.setEditModeState(EditModeState.SHOWING)
+ }
+ }
+ }
+
private fun onOpenWidgetPicker() {
lifecycleScope.launch {
communalViewModel.onOpenWidgetPicker(
@@ -150,9 +168,11 @@
private fun onEditDone() {
lifecycleScope.launch {
+ communalViewModel.cleanupEditModeState()
+
communalViewModel.changeScene(
CommunalScenes.Communal,
- CommunalTransitionKeys.SimpleFade
+ CommunalTransitionKeys.FromEditMode
)
// Wait for the current scene to be idle on communal.
@@ -192,6 +212,7 @@
override fun onDestroy() {
super.onDestroy()
+ communalViewModel.cleanupEditModeState()
communalViewModel.setEditModeOpen(false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 14eb972..49d00af 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -114,13 +114,26 @@
powerInteractor.isAwake,
keyguardInteractor.isAodAvailable,
communalInteractor.isIdleOnCommunal,
+ communalInteractor.editModeOpen,
keyguardInteractor.isKeyguardOccluded,
)
.filterRelevantKeyguardStateAnd {
(isAlternateBouncerShowing, isPrimaryBouncerShowing, _, _, _) ->
!isAlternateBouncerShowing && !isPrimaryBouncerShowing
}
- .collect { (_, _, isAwake, isAodAvailable, isIdleOnCommunal, isOccluded) ->
+ .collect {
+ (
+ _,
+ _,
+ isAwake,
+ isAodAvailable,
+ isIdleOnCommunal,
+ isCommunalEditMode,
+ isOccluded) ->
+ // When unlocking over glanceable hub to enter edit mode, transitioning directly
+ // to GONE prevents the lockscreen flash. Let listenForAlternateBouncerToGone
+ // handle it.
+ if (isCommunalEditMode) return@collect
val to =
if (!isAwake) {
if (isAodAvailable) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index 3a43b1c..069f65b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -105,7 +105,17 @@
is ObservableTransitionState.Transition ->
when {
transitionState.fromScene == Scenes.Lockscreen &&
- transitionState.toScene == Scenes.Gone -> flowOf(true)
+ transitionState.toScene == Scenes.Gone ->
+ sceneInteractor
+ .get()
+ .isTransitionUserInputOngoing
+ .flatMapLatestConflated { isUserInputOngoing ->
+ if (isUserInputOngoing) {
+ isDeviceEntered
+ } else {
+ flowOf(true)
+ }
+ }
transitionState.fromScene == Scenes.Bouncer &&
transitionState.toScene == Scenes.Gone ->
transitionState.progress.map { progress ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index 940f423..f5c521a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -32,6 +32,7 @@
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.ui.SystemBarUtilsProxy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -48,6 +49,7 @@
constructor(
keyguardClockInteractor: KeyguardClockInteractor,
@Application private val applicationScope: CoroutineScope,
+ aodNotificationIconViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
notifsKeyguardInteractor: NotificationsKeyguardInteractor,
@get:VisibleForTesting val shadeInteractor: ShadeInteractor,
private val systemBarUtils: SystemBarUtilsProxy,
@@ -105,8 +107,13 @@
initialValue = false
)
- val isAodIconsVisible: StateFlow<Boolean> =
- notifsKeyguardInteractor.areNotificationsFullyHidden.stateIn(
+ // To translate elements below smartspace in weather clock to avoid overlapping between date
+ // element in weather clock and aod icons
+ val isAodIconsVisible: StateFlow<Boolean> = combine(aodNotificationIconViewModel.icons.map {
+ it.visibleIcons.isNotEmpty()
+ }, notifsKeyguardInteractor.areNotificationsFullyHidden) { hasIcons, visible ->
+ hasIcons && visible
+ }.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue = false
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java
index fbb84de..4496b25 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java
@@ -16,7 +16,9 @@
package com.android.systemui.media.dialog;
-import androidx.annotation.IntDef;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.res.R;
@@ -46,40 +48,50 @@
int TYPE_PAIR_NEW_DEVICE = 2;
}
- public MediaItem() {
- this.mMediaDeviceOptional = Optional.empty();
- this.mTitle = null;
- this.mMediaItemType = MediaItemType.TYPE_PAIR_NEW_DEVICE;
+ /**
+ * Returns a new {@link MediaItemType#TYPE_DEVICE} {@link MediaItem} with its {@link
+ * #getMediaDevice() media device} set to {@code device} and its title set to {@code device}'s
+ * name.
+ */
+ public static MediaItem createDeviceMediaItem(@NonNull MediaDevice device) {
+ return new MediaItem(device, device.getName(), MediaItemType.TYPE_DEVICE);
}
- public MediaItem(String title, int mediaItemType) {
- this.mMediaDeviceOptional = Optional.empty();
+ /**
+ * Returns a new {@link MediaItemType#TYPE_PAIR_NEW_DEVICE} {@link MediaItem} with both {@link
+ * #getMediaDevice() media device} and title set to {@code null}.
+ */
+ public static MediaItem createPairNewDeviceMediaItem() {
+ return new MediaItem(
+ /* device */ null, /* title */ null, MediaItemType.TYPE_PAIR_NEW_DEVICE);
+ }
+
+ /**
+ * Returns a new {@link MediaItemType#TYPE_GROUP_DIVIDER} {@link MediaItem} with the specified
+ * title and a {@code null} {@link #getMediaDevice() media device}.
+ */
+ public static MediaItem createGroupDividerMediaItem(@Nullable String title) {
+ return new MediaItem(/* device */ null, title, MediaItemType.TYPE_GROUP_DIVIDER);
+ }
+
+ private MediaItem(
+ @Nullable MediaDevice device, @Nullable String title, @MediaItemType int type) {
+ this.mMediaDeviceOptional = Optional.ofNullable(device);
this.mTitle = title;
- this.mMediaItemType = mediaItemType;
- }
-
- public MediaItem(MediaDevice mediaDevice) {
- this.mMediaDeviceOptional = Optional.of(mediaDevice);
- this.mTitle = mediaDevice.getName();
- this.mMediaItemType = MediaItemType.TYPE_DEVICE;
+ this.mMediaItemType = type;
}
public Optional<MediaDevice> getMediaDevice() {
return mMediaDeviceOptional;
}
- /**
- * Get layout id based on media item Type.
- */
- public static int getMediaLayoutId(int mediaItemType) {
- switch (mediaItemType) {
- case MediaItemType.TYPE_DEVICE:
- case MediaItemType.TYPE_PAIR_NEW_DEVICE:
- return R.layout.media_output_list_item_advanced;
- case MediaItemType.TYPE_GROUP_DIVIDER:
- default:
- return R.layout.media_output_list_group_divider;
- }
+ /** Get layout id based on media item Type. */
+ public static int getMediaLayoutId(@MediaItemType int mediaItemType) {
+ return switch (mediaItemType) {
+ case MediaItemType.TYPE_DEVICE, MediaItemType.TYPE_PAIR_NEW_DEVICE ->
+ R.layout.media_output_list_item_advanced;
+ default -> R.layout.media_output_list_group_divider;
+ };
}
public String getTitle() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index c2cfdbe..1e86563 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -68,6 +68,7 @@
import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.drawable.IconCompat;
+import com.android.internal.annotations.GuardedBy;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -656,10 +657,16 @@
if (DEBUG) {
Log.d(TAG, "No connected media device or muting expected device exist.");
}
- return categorizeMediaItems(null, devices, needToHandleMutingExpectedDevice);
+ return categorizeMediaItemsLocked(
+ /* connectedMediaDevice */ null,
+ devices,
+ needToHandleMutingExpectedDevice);
}
// selected device exist
- return categorizeMediaItems(connectedMediaDevice, devices, false);
+ return categorizeMediaItemsLocked(
+ connectedMediaDevice,
+ devices,
+ /* needToHandleMutingExpectedDevice */ false);
}
// To keep the same list order
final List<MediaDevice> targetMediaDevices = new ArrayList<>();
@@ -682,8 +689,9 @@
devices.removeAll(targetMediaDevices);
targetMediaDevices.addAll(devices);
}
- List<MediaItem> finalMediaItems = targetMediaDevices.stream().map(
- MediaItem::new).collect(Collectors.toList());
+ List<MediaItem> finalMediaItems = targetMediaDevices.stream()
+ .map(MediaItem::createDeviceMediaItem)
+ .collect(Collectors.toList());
dividerItems.forEach(finalMediaItems::add);
attachConnectNewDeviceItemIfNeeded(finalMediaItems);
return finalMediaItems;
@@ -694,51 +702,50 @@
* Initial categorization of current devices, will not be called for updates to the devices
* list.
*/
- private List<MediaItem> categorizeMediaItems(MediaDevice connectedMediaDevice,
+ @GuardedBy("mMediaDevicesLock")
+ private List<MediaItem> categorizeMediaItemsLocked(MediaDevice connectedMediaDevice,
List<MediaDevice> devices,
boolean needToHandleMutingExpectedDevice) {
- synchronized (mMediaDevicesLock) {
- List<MediaItem> finalMediaItems = new ArrayList<>();
- Set<String> selectedDevicesIds = getSelectedMediaDevice().stream().map(
- MediaDevice::getId).collect(Collectors.toSet());
- if (connectedMediaDevice != null) {
- selectedDevicesIds.add(connectedMediaDevice.getId());
- }
- boolean suggestedDeviceAdded = false;
- boolean displayGroupAdded = false;
- for (MediaDevice device : devices) {
- if (needToHandleMutingExpectedDevice && device.isMutingExpectedDevice()) {
- finalMediaItems.add(0, new MediaItem(device));
- } else if (!needToHandleMutingExpectedDevice && selectedDevicesIds.contains(
- device.getId())) {
- finalMediaItems.add(0, new MediaItem(device));
- } else {
- if (device.isSuggestedDevice() && !suggestedDeviceAdded) {
- attachGroupDivider(finalMediaItems, mContext.getString(
- R.string.media_output_group_title_suggested_device));
- suggestedDeviceAdded = true;
- } else if (!device.isSuggestedDevice() && !displayGroupAdded) {
- attachGroupDivider(finalMediaItems, mContext.getString(
- R.string.media_output_group_title_speakers_and_displays));
- displayGroupAdded = true;
- }
- finalMediaItems.add(new MediaItem(device));
- }
- }
- attachConnectNewDeviceItemIfNeeded(finalMediaItems);
- return finalMediaItems;
+ List<MediaItem> finalMediaItems = new ArrayList<>();
+ Set<String> selectedDevicesIds = getSelectedMediaDevice().stream()
+ .map(MediaDevice::getId)
+ .collect(Collectors.toSet());
+ if (connectedMediaDevice != null) {
+ selectedDevicesIds.add(connectedMediaDevice.getId());
}
+ boolean suggestedDeviceAdded = false;
+ boolean displayGroupAdded = false;
+ for (MediaDevice device : devices) {
+ if (needToHandleMutingExpectedDevice && device.isMutingExpectedDevice()) {
+ finalMediaItems.add(0, MediaItem.createDeviceMediaItem(device));
+ } else if (!needToHandleMutingExpectedDevice && selectedDevicesIds.contains(
+ device.getId())) {
+ finalMediaItems.add(0, MediaItem.createDeviceMediaItem(device));
+ } else {
+ if (device.isSuggestedDevice() && !suggestedDeviceAdded) {
+ attachGroupDivider(finalMediaItems, mContext.getString(
+ R.string.media_output_group_title_suggested_device));
+ suggestedDeviceAdded = true;
+ } else if (!device.isSuggestedDevice() && !displayGroupAdded) {
+ attachGroupDivider(finalMediaItems, mContext.getString(
+ R.string.media_output_group_title_speakers_and_displays));
+ displayGroupAdded = true;
+ }
+ finalMediaItems.add(MediaItem.createDeviceMediaItem(device));
+ }
+ }
+ attachConnectNewDeviceItemIfNeeded(finalMediaItems);
+ return finalMediaItems;
}
private void attachGroupDivider(List<MediaItem> mediaItems, String title) {
- mediaItems.add(
- new MediaItem(title, MediaItem.MediaItemType.TYPE_GROUP_DIVIDER));
+ mediaItems.add(MediaItem.createGroupDividerMediaItem(title));
}
private void attachConnectNewDeviceItemIfNeeded(List<MediaItem> mediaItems) {
// Attach "Connect a device" item only when current output is not remote and not a group
if (!isCurrentConnectedDeviceRemote() && getSelectedMediaDevice().size() == 1) {
- mediaItems.add(new MediaItem());
+ mediaItems.add(MediaItem.createPairNewDeviceMediaItem());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/model/MediaProjectionState.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/model/MediaProjectionState.kt
index 1d5f6f5..de300b2 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/model/MediaProjectionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/model/MediaProjectionState.kt
@@ -20,7 +20,21 @@
/** Represents the state of media projection. */
sealed interface MediaProjectionState {
- object NotProjecting : MediaProjectionState
- object EntireScreen : MediaProjectionState
- data class SingleTask(val task: RunningTaskInfo) : MediaProjectionState
+ /** There is no media being projected. */
+ data object NotProjecting : MediaProjectionState
+
+ /**
+ * Media is currently being projected.
+ *
+ * @property hostPackage the package name of the app that is receiving the content of the media
+ * projection (aka which app the phone screen contents are being sent to).
+ */
+ sealed class Projecting(open val hostPackage: String) : MediaProjectionState {
+ /** The entire screen is being projected. */
+ data class EntireScreen(override val hostPackage: String) : Projecting(hostPackage)
+
+ /** Only a single task is being projected. */
+ data class SingleTask(override val hostPackage: String, val task: RunningTaskInfo) :
+ Projecting(hostPackage)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
index 3ce0a1e0..8a9adc7 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
@@ -64,6 +64,10 @@
}
}
+ override suspend fun stopProjecting() {
+ withContext(backgroundDispatcher) { mediaProjectionManager.stopActiveProjection() }
+ }
+
override val mediaProjectionState: Flow<MediaProjectionState> =
conflatedCallbackFlow {
val callback =
@@ -83,7 +87,9 @@
session: ContentRecordingSession?
) {
Log.d(TAG, "MediaProjectionManager.Callback#onSessionStarted: $session")
- launch { trySendWithFailureLogging(stateForSession(session), TAG) }
+ launch {
+ trySendWithFailureLogging(stateForSession(info, session), TAG)
+ }
}
}
mediaProjectionManager.addCallback(callback, handler)
@@ -95,19 +101,23 @@
initialValue = MediaProjectionState.NotProjecting,
)
- private suspend fun stateForSession(session: ContentRecordingSession?): MediaProjectionState {
+ private suspend fun stateForSession(
+ info: MediaProjectionInfo,
+ session: ContentRecordingSession?
+ ): MediaProjectionState {
if (session == null) {
return MediaProjectionState.NotProjecting
}
+
+ val hostPackage = info.packageName
if (session.contentToRecord == RECORD_CONTENT_DISPLAY || session.tokenToRecord == null) {
- return MediaProjectionState.EntireScreen
+ return MediaProjectionState.Projecting.EntireScreen(hostPackage)
}
val matchingTask =
tasksRepository.findRunningTaskFromWindowContainerToken(
checkNotNull(session.tokenToRecord)
- )
- ?: return MediaProjectionState.EntireScreen
- return MediaProjectionState.SingleTask(matchingTask)
+ ) ?: return MediaProjectionState.Projecting.EntireScreen(hostPackage)
+ return MediaProjectionState.Projecting.SingleTask(hostPackage, matchingTask)
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
index 21300db..50182d7 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
@@ -26,6 +26,9 @@
/** Switches the task that should be projected. */
suspend fun switchProjectedTask(task: RunningTaskInfo)
+ /** Stops the currently active projection. */
+ suspend fun stopProjecting()
+
/** Represents the current [MediaProjectionState]. */
val mediaProjectionState: Flow<MediaProjectionState>
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
index c232d4d..118639c 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
@@ -57,7 +57,7 @@
mediaProjectionRepository.mediaProjectionState.flatMapLatest { projectionState ->
Log.d(TAG, "MediaProjectionState -> $projectionState")
when (projectionState) {
- is MediaProjectionState.SingleTask -> {
+ is MediaProjectionState.Projecting.SingleTask -> {
val projectedTask = projectionState.task
tasksRepository.foregroundTask.map { foregroundTask ->
if (hasForegroundTaskSwitched(projectedTask, foregroundTask)) {
@@ -67,7 +67,7 @@
}
}
}
- is MediaProjectionState.EntireScreen,
+ is MediaProjectionState.Projecting.EntireScreen,
is MediaProjectionState.NotProjecting -> {
flowOf(TaskSwitchState.NotProjectingTask)
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 0e819c2..07289cb 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -2028,12 +2028,15 @@
getBarTransitions().setBackgroundOverrideAlpha(1f);
}
}
- updateScreenPinningGestures();
+
+ // Update the window layout params when the nav mode changes as that will affect the
+ // system gesture insets
+ setNavBarMode(mode);
+ repositionNavigationBar(mCurrentRotation);
if (!canShowSecondaryHandle()) {
resetSecondaryHandle();
}
- setNavBarMode(mode);
mView.setShouldShowSwipeUpUi(mOverviewProxyService.shouldShowSwipeUpUI());
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
index 79720c1..5637115 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
@@ -35,6 +35,7 @@
import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
import com.android.systemui.screenrecord.RecordingController
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
+import com.android.systemui.screenrecord.data.repository.ScreenRecordRepository
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
@@ -47,6 +48,7 @@
@Application private val context: Context,
@Main private val mainContext: CoroutineContext,
@Background private val backgroundContext: CoroutineContext,
+ private val screenRecordRepository: ScreenRecordRepository,
private val recordingController: RecordingController,
private val keyguardInteractor: KeyguardInteractor,
private val keyguardDismissUtil: KeyguardDismissUtil,
@@ -65,8 +67,7 @@
Log.d(TAG, "Cancelling countdown")
withContext(backgroundContext) { recordingController.cancelCountdown() }
}
- is ScreenRecordModel.Recording ->
- withContext(backgroundContext) { recordingController.stopRecording() }
+ is ScreenRecordModel.Recording -> screenRecordRepository.stopRecording()
is ScreenRecordModel.DoingNothing ->
withContext(mainContext) {
showPrompt(action.expandable, user.identifier)
@@ -122,8 +123,7 @@
controller,
animateBackgroundBoundsChange = true,
)
- }
- ?: dialog.show()
+ } ?: dialog.show()
} else {
dialog.show()
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt
index d59d220..9eeb3b9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt
@@ -28,6 +28,7 @@
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withContext
/**
* Repository storing information about the state of screen recording.
@@ -38,6 +39,9 @@
interface ScreenRecordRepository {
/** The current screen recording state. Note that this is a cold flow. */
val screenRecordState: Flow<ScreenRecordModel>
+
+ /** Stops the recording. */
+ suspend fun stopRecording()
}
@SysUISingleton
@@ -90,4 +94,8 @@
ScreenRecordModel.DoingNothing
}
}
+
+ override suspend fun stopRecording() {
+ withContext(bgCoroutineContext) { recordingController.stopRecording() }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt
index c3d37fb..086a32d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt
@@ -16,11 +16,37 @@
package com.android.systemui.statusbar.chips.domain.interactor
+import android.view.View
+import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
+import com.android.systemui.statusbar.phone.SystemUIDialog
import kotlinx.coroutines.flow.StateFlow
/** Interface for an interactor that knows the state of a single type of ongoing activity chip. */
interface OngoingActivityChipInteractor {
/** A flow modeling the chip that should be shown. */
val chip: StateFlow<OngoingActivityChipModel>
+
+ companion object {
+ /** Creates a chip click listener that launches a dialog created by [dialogDelegate]. */
+ fun createDialogLaunchOnClickListener(
+ dialogDelegate: SystemUIDialog.Delegate,
+ dialogTransitionAnimator: DialogTransitionAnimator,
+ ): View.OnClickListener {
+ return View.OnClickListener { view ->
+ val dialog = dialogDelegate.createDialog()
+ val launchableView =
+ view.requireViewById<ChipBackgroundContainer>(
+ R.id.ongoing_activity_chip_background
+ )
+ // TODO(b/343699052): This makes a beautiful animate-in, but the
+ // animate-out looks odd because the dialog animates back into the chip
+ // but then the chip disappears. If we aren't able to address
+ // b/343699052 in time for launch, we should just use `dialog.show`.
+ dialogTransitionAnimator.showFromView(dialog, launchableView)
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
index ac16d26..6611434 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.chips.mediaprojection.domain.interactor
+import android.content.pm.PackageManager
+import androidx.annotation.DrawableRes
+import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
@@ -24,7 +27,12 @@
import com.android.systemui.mediaprojection.data.repository.MediaProjectionRepository
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor.Companion.createDialogLaunchOnClickListener
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndCastToOtherDeviceDialogDelegate
+import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndShareToAppDialogDelegate
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.Utils
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -32,6 +40,7 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/**
* Interactor for media-projection-related chips in the status bar.
@@ -47,33 +56,88 @@
class MediaProjectionChipInteractor
@Inject
constructor(
- @Application scope: CoroutineScope,
- mediaProjectionRepository: MediaProjectionRepository,
- val systemClock: SystemClock,
+ @Application private val scope: CoroutineScope,
+ private val mediaProjectionRepository: MediaProjectionRepository,
+ private val packageManager: PackageManager,
+ private val systemClock: SystemClock,
+ private val dialogFactory: SystemUIDialog.Factory,
+ private val dialogTransitionAnimator: DialogTransitionAnimator,
) : OngoingActivityChipInteractor {
override val chip: StateFlow<OngoingActivityChipModel> =
mediaProjectionRepository.mediaProjectionState
.map { state ->
when (state) {
is MediaProjectionState.NotProjecting -> OngoingActivityChipModel.Hidden
- is MediaProjectionState.EntireScreen,
- is MediaProjectionState.SingleTask -> {
- // TODO(b/332662551): Distinguish between cast-to-other-device and
- // share-to-app.
- OngoingActivityChipModel.Shown(
- icon =
- Icon.Resource(
- R.drawable.ic_cast_connected,
- ContentDescription.Resource(R.string.accessibility_casting)
- ),
- // TODO(b/332662551): See if we can use a MediaProjection API to fetch
- // this time.
- startTimeMs = systemClock.elapsedRealtime()
- ) {
- // TODO(b/332662551): Implement the pause dialog.
+ is MediaProjectionState.Projecting -> {
+ if (isProjectionToOtherDevice(state.hostPackage)) {
+ createCastToOtherDeviceChip()
+ } else {
+ createShareToAppChip()
}
}
}
}
.stateIn(scope, SharingStarted.WhileSubscribed(), OngoingActivityChipModel.Hidden)
+
+ /** Stops the currently active projection. */
+ fun stopProjecting() {
+ scope.launch { mediaProjectionRepository.stopProjecting() }
+ }
+
+ /**
+ * Returns true iff projecting to the given [packageName] means that we're projecting to a
+ * *different* device (as opposed to projecting to some application on *this* device).
+ */
+ private fun isProjectionToOtherDevice(packageName: String?): Boolean {
+ // The [isHeadlessRemoteDisplayProvider] check approximates whether a projection is to a
+ // different device or the same device, because headless remote display packages are the
+ // only kinds of packages that do cast-to-other-device. This isn't exactly perfect,
+ // because it means that any projection by those headless remote display packages will be
+ // marked as going to a different device, even if that isn't always true. See b/321078669.
+ return Utils.isHeadlessRemoteDisplayProvider(packageManager, packageName)
+ }
+
+ private fun createCastToOtherDeviceChip(): OngoingActivityChipModel.Shown {
+ return OngoingActivityChipModel.Shown(
+ icon =
+ Icon.Resource(
+ CAST_TO_OTHER_DEVICE_ICON,
+ ContentDescription.Resource(R.string.accessibility_casting)
+ ),
+ // TODO(b/332662551): Maybe use a MediaProjection API to fetch this time.
+ startTimeMs = systemClock.elapsedRealtime(),
+ createDialogLaunchOnClickListener(
+ castToOtherDeviceDialogDelegate,
+ dialogTransitionAnimator,
+ ),
+ )
+ }
+
+ private val castToOtherDeviceDialogDelegate =
+ EndCastToOtherDeviceDialogDelegate(
+ dialogFactory,
+ this@MediaProjectionChipInteractor,
+ )
+
+ private fun createShareToAppChip(): OngoingActivityChipModel.Shown {
+ return OngoingActivityChipModel.Shown(
+ // TODO(b/332662551): Use the right content description.
+ icon = Icon.Resource(SHARE_TO_APP_ICON, contentDescription = null),
+ // TODO(b/332662551): Maybe use a MediaProjection API to fetch this time.
+ startTimeMs = systemClock.elapsedRealtime(),
+ createDialogLaunchOnClickListener(shareToAppDialogDelegate, dialogTransitionAnimator),
+ )
+ }
+
+ private val shareToAppDialogDelegate =
+ EndShareToAppDialogDelegate(
+ dialogFactory,
+ this@MediaProjectionChipInteractor,
+ )
+
+ companion object {
+ // TODO(b/332662551): Use the right icon.
+ @DrawableRes val SHARE_TO_APP_ICON = R.drawable.ic_screenshot_share
+ @DrawableRes val CAST_TO_OTHER_DEVICE_ICON = R.drawable.ic_cast_connected
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegate.kt
new file mode 100644
index 0000000..33cec97
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegate.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.mediaprojection.ui.view
+
+import android.os.Bundle
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+
+/** A dialog that lets the user stop an ongoing cast-screen-to-other-device event. */
+class EndCastToOtherDeviceDialogDelegate(
+ private val systemUIDialogFactory: SystemUIDialog.Factory,
+ private val interactor: MediaProjectionChipInteractor,
+) : SystemUIDialog.Delegate {
+ override fun createDialog(): SystemUIDialog {
+ return systemUIDialogFactory.create(this)
+ }
+
+ override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ with(dialog) {
+ setIcon(MediaProjectionChipInteractor.CAST_TO_OTHER_DEVICE_ICON)
+ setTitle(R.string.cast_to_other_device_stop_dialog_title)
+ // TODO(b/332662551): Use a different message if they're sharing just a single app.
+ setMessage(R.string.cast_to_other_device_stop_dialog_message)
+ // No custom on-click, because the dialog will automatically be dismissed when the
+ // button is clicked anyway.
+ setNegativeButton(R.string.close_dialog_button, /* onClick= */ null)
+ setPositiveButton(R.string.cast_to_other_device_stop_dialog_button) { _, _ ->
+ interactor.stopProjecting()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegate.kt
new file mode 100644
index 0000000..3a863b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegate.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.mediaprojection.ui.view
+
+import android.os.Bundle
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+
+/** A dialog that lets the user stop an ongoing share-screen-to-app event. */
+class EndShareToAppDialogDelegate(
+ private val systemUIDialogFactory: SystemUIDialog.Factory,
+ private val interactor: MediaProjectionChipInteractor,
+) : SystemUIDialog.Delegate {
+ override fun createDialog(): SystemUIDialog {
+ return systemUIDialogFactory.create(this)
+ }
+
+ override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ with(dialog) {
+ setIcon(MediaProjectionChipInteractor.SHARE_TO_APP_ICON)
+ setTitle(R.string.share_to_app_stop_dialog_title)
+ // TODO(b/332662551): Use a different message if they're sharing just a single app.
+ setMessage(R.string.share_to_app_stop_dialog_message)
+ // No custom on-click, because the dialog will automatically be dismissed when the
+ // button is clicked anyway.
+ setNegativeButton(R.string.close_dialog_button, /* onClick= */ null)
+ setPositiveButton(R.string.share_to_app_stop_dialog_button) { _, _ ->
+ interactor.stopProjecting()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
index 585ff5f..4959b09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.chips.screenrecord.domain.interactor
+import androidx.annotation.DrawableRes
+import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -23,7 +25,10 @@
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.ScreenRecordRepository
import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor.Companion.createDialogLaunchOnClickListener
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.screenrecord.ui.view.EndScreenRecordingDialogDelegate
+import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -31,15 +36,18 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/** Interactor for the screen recording chip shown in the status bar. */
@SysUISingleton
class ScreenRecordChipInteractor
@Inject
constructor(
- @Application scope: CoroutineScope,
- screenRecordRepository: ScreenRecordRepository,
- val systemClock: SystemClock,
+ @Application private val scope: CoroutineScope,
+ private val screenRecordRepository: ScreenRecordRepository,
+ private val systemClock: SystemClock,
+ private val dialogFactory: SystemUIDialog.Factory,
+ private val dialogTransitionAnimator: DialogTransitionAnimator,
) : OngoingActivityChipInteractor {
override val chip: StateFlow<OngoingActivityChipModel> =
screenRecordRepository.screenRecordState
@@ -51,16 +59,29 @@
is ScreenRecordModel.Recording ->
OngoingActivityChipModel.Shown(
// TODO(b/332662551): Also provide a content description.
- icon =
- Icon.Resource(
- R.drawable.stat_sys_screen_record,
- contentDescription = null
- ),
- startTimeMs = systemClock.elapsedRealtime()
- ) {
- // TODO(b/332662551): Implement the pause dialog.
- }
+ icon = Icon.Resource(ICON, contentDescription = null),
+ startTimeMs = systemClock.elapsedRealtime(),
+ createDialogLaunchOnClickListener(
+ dialogDelegate,
+ dialogTransitionAnimator
+ ),
+ )
}
}
.stateIn(scope, SharingStarted.WhileSubscribed(), OngoingActivityChipModel.Hidden)
+
+ /** Stops the recording. */
+ fun stopRecording() {
+ scope.launch { screenRecordRepository.stopRecording() }
+ }
+
+ private val dialogDelegate =
+ EndScreenRecordingDialogDelegate(
+ dialogFactory,
+ this@ScreenRecordChipInteractor,
+ )
+
+ companion object {
+ @DrawableRes val ICON = R.drawable.ic_screenrecord
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegate.kt
new file mode 100644
index 0000000..b8e8cfa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegate.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.screenrecord.ui.view
+
+import android.os.Bundle
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+
+/** A dialog that lets the user stop an ongoing screen recording. */
+class EndScreenRecordingDialogDelegate(
+ private val systemUIDialogFactory: SystemUIDialog.Factory,
+ private val interactor: ScreenRecordChipInteractor,
+) : SystemUIDialog.Delegate {
+
+ override fun createDialog(): SystemUIDialog {
+ return systemUIDialogFactory.create(this)
+ }
+
+ override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ with(dialog) {
+ setIcon(ScreenRecordChipInteractor.ICON)
+ setTitle(R.string.screenrecord_stop_dialog_title)
+ // TODO(b/332662551): Use a different message if they're sharing just a single app.
+ setMessage(R.string.screenrecord_stop_dialog_message)
+ // No custom on-click, because the dialog will automatically be dismissed when the
+ // button is clicked anyway.
+ setNegativeButton(R.string.close_dialog_button, /* onClick= */ null)
+ setPositiveButton(R.string.screenrecord_stop_dialog_button) { _, _ ->
+ interactor.stopRecording()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
index e5fc4e2..800d7fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt
@@ -469,7 +469,7 @@
shadeControllerLazy.get().collapseShadeForActivityStart()
}
if (communalHub()) {
- communalSceneInteractor.snapToScene(CommunalScenes.Blank)
+ communalSceneInteractor.snapToSceneForActivityStart(CommunalScenes.Blank)
}
return deferred
}
@@ -556,7 +556,7 @@
override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) {
super.onTransitionAnimationStart(isExpandingFullyAbove)
if (communalHub()) {
- communalSceneInteractor.snapToScene(
+ communalSceneInteractor.snapToSceneForActivityStart(
CommunalScenes.Blank,
ActivityTransitionAnimator.TIMINGS.totalDuration
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index a2ec1f2..44b5baf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -94,7 +94,7 @@
is OngoingActivityChipModel.Shown -> {
IconViewBinder.bind(chipModel.icon, chipIconView)
ChipChronometerBinder.bind(chipModel.startTimeMs, chipTimeView)
- // TODO(b/332662551): Attach click listener to chip
+ chipView.setOnClickListener(chipModel.onClickListener)
listener.onOngoingActivityStatusChanged(
hasOngoingActivity = true
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt
index 7669524..11740a8 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt
@@ -27,6 +27,10 @@
private val _screen = MutableStateFlow(Screen.TUTORIAL_SELECTION)
val screen: StateFlow<Screen> = _screen
+ fun goTo(screen: Screen) {
+ _screen.value = screen
+ }
+
class Factory @Inject constructor() : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TutorialSelectionViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TutorialSelectionViewModel.kt
deleted file mode 100644
index 1a8272d8..0000000
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TutorialSelectionViewModel.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.touchpad.tutorial.ui
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-
-class TutorialSelectionViewModel : ViewModel()
-
-class TutorialSelectionViewModelFactory : ViewModelProvider.Factory {
-
- @Suppress("UNCHECKED_CAST")
- override fun <T : ViewModel> create(modelClass: Class<T>): T {
- return TutorialSelectionViewModel() as T
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
index 09dd909..b7629c7 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
@@ -19,6 +19,7 @@
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.Lifecycle.State.STARTED
@@ -33,8 +34,6 @@
import com.android.systemui.touchpad.tutorial.ui.Screen.HOME_GESTURE
import com.android.systemui.touchpad.tutorial.ui.Screen.TUTORIAL_SELECTION
import com.android.systemui.touchpad.tutorial.ui.TouchpadTutorialViewModel
-import com.android.systemui.touchpad.tutorial.ui.TutorialSelectionViewModel
-import com.android.systemui.touchpad.tutorial.ui.TutorialSelectionViewModelFactory
import javax.inject.Inject
class TouchpadTutorialActivity
@@ -45,27 +44,31 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContent { PlatformTheme { TouchpadTutorialScreen(viewModelFactory) } }
+ enableEdgeToEdge()
+ setContent {
+ PlatformTheme { TouchpadTutorialScreen(viewModelFactory, closeTutorial = { finish() }) }
+ }
}
}
@Composable
-fun TouchpadTutorialScreen(viewModelFactory: ViewModelProvider.Factory) {
+fun TouchpadTutorialScreen(viewModelFactory: ViewModelProvider.Factory, closeTutorial: () -> Unit) {
val vm = viewModel<TouchpadTutorialViewModel>(factory = viewModelFactory)
val activeScreen by vm.screen.collectAsStateWithLifecycle(STARTED)
when (activeScreen) {
- TUTORIAL_SELECTION -> TutorialSelectionScreen()
+ TUTORIAL_SELECTION ->
+ TutorialSelectionScreen(
+ onBackTutorialClicked = { vm.goTo(BACK_GESTURE) },
+ onHomeTutorialClicked = { vm.goTo(HOME_GESTURE) },
+ onActionKeyTutorialClicked = {},
+ onDoneButtonClicked = closeTutorial
+ )
BACK_GESTURE -> BackGestureTutorialScreen()
HOME_GESTURE -> HomeGestureTutorialScreen()
}
}
@Composable
-fun TutorialSelectionScreen() {
- val vm = viewModel<TutorialSelectionViewModel>(factory = TutorialSelectionViewModelFactory())
-}
-
-@Composable
fun BackGestureTutorialScreen() {
val vm = viewModel<BackGestureTutorialViewModel>(factory = GestureViewModelFactory())
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialSelectionScreen.kt
new file mode 100644
index 0000000..532eb1b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialSelectionScreen.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.touchpad.tutorial.ui.view
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.android.systemui.res.R
+
+@Composable
+fun TutorialSelectionScreen(
+ onBackTutorialClicked: () -> Unit,
+ onHomeTutorialClicked: () -> Unit,
+ onActionKeyTutorialClicked: () -> Unit,
+ onDoneButtonClicked: () -> Unit,
+) {
+ Column(
+ verticalArrangement = Arrangement.Center,
+ modifier =
+ Modifier.background(
+ color = MaterialTheme.colorScheme.surfaceContainer,
+ )
+ .fillMaxSize()
+ ) {
+ TutorialSelectionButtons(
+ onBackTutorialClicked = onBackTutorialClicked,
+ onHomeTutorialClicked = onHomeTutorialClicked,
+ onActionKeyTutorialClicked = onActionKeyTutorialClicked,
+ modifier = Modifier.padding(60.dp)
+ )
+ DoneButton(
+ onDoneButtonClicked = onDoneButtonClicked,
+ modifier = Modifier.padding(horizontal = 60.dp)
+ )
+ }
+}
+
+@Composable
+private fun TutorialSelectionButtons(
+ onBackTutorialClicked: () -> Unit,
+ onHomeTutorialClicked: () -> Unit,
+ onActionKeyTutorialClicked: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(20.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = modifier
+ ) {
+ TutorialButton(
+ text = stringResource(R.string.touchpad_tutorial_back_gesture_button),
+ onClick = onBackTutorialClicked,
+ color = MaterialTheme.colorScheme.primary,
+ modifier = Modifier.weight(1f)
+ )
+ TutorialButton(
+ text = stringResource(R.string.touchpad_tutorial_home_gesture_button),
+ onClick = onHomeTutorialClicked,
+ color = MaterialTheme.colorScheme.secondary,
+ modifier = Modifier.weight(1f)
+ )
+ TutorialButton(
+ text = stringResource(R.string.touchpad_tutorial_action_key_button),
+ onClick = onActionKeyTutorialClicked,
+ color = MaterialTheme.colorScheme.tertiary,
+ modifier = Modifier.weight(1f)
+ )
+ }
+}
+
+@Composable
+private fun TutorialButton(
+ text: String,
+ onClick: () -> Unit,
+ color: Color,
+ modifier: Modifier = Modifier
+) {
+ Button(
+ onClick = onClick,
+ shape = RoundedCornerShape(16.dp),
+ colors = ButtonDefaults.buttonColors(containerColor = color),
+ modifier = modifier.aspectRatio(0.66f)
+ ) {
+ Text(text = text, style = MaterialTheme.typography.headlineLarge)
+ }
+}
+
+@Composable
+private fun DoneButton(onDoneButtonClicked: () -> Unit, modifier: Modifier = Modifier) {
+ Row(
+ horizontalArrangement = Arrangement.End,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = modifier.fillMaxWidth()
+ ) {
+ Button(onClick = onDoneButtonClicked) {
+ Text(stringResource(R.string.touchpad_tutorial_done_button))
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index 7076954..cc7dec56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -26,6 +26,7 @@
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.Point
+import android.graphics.Rect
import android.graphics.drawable.BitmapDrawable
import android.hardware.biometrics.BiometricFingerprintConstants
import android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT
@@ -87,9 +88,6 @@
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4
-import platform.test.runner.parameterized.Parameter
-import platform.test.runner.parameterized.Parameters
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -97,6 +95,8 @@
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
private const val USER_ID = 4
private const val REQUEST_ID = 4L
@@ -135,6 +135,27 @@
private val defaultLogoDescription = "Test Android App"
private val logoDescriptionFromApp = "Test Cake App"
private val packageNameForLogoWithOverrides = "should.use.overridden.logo"
+ /** Prompt panel size padding */
+ private val smallHorizontalGuidelinePadding =
+ context.resources.getDimensionPixelSize(
+ R.dimen.biometric_prompt_land_small_horizontal_guideline_padding
+ )
+ private val udfpsHorizontalGuidelinePadding =
+ context.resources.getDimensionPixelSize(
+ R.dimen.biometric_prompt_two_pane_udfps_horizontal_guideline_padding
+ )
+ private val udfpsHorizontalShorterGuidelinePadding =
+ context.resources.getDimensionPixelSize(
+ R.dimen.biometric_prompt_two_pane_udfps_shorter_horizontal_guideline_padding
+ )
+ private val mediumTopGuidelinePadding =
+ context.resources.getDimensionPixelSize(
+ R.dimen.biometric_prompt_one_pane_medium_top_guideline_padding
+ )
+ private val mediumHorizontalGuidelinePadding =
+ context.resources.getDimensionPixelSize(
+ R.dimen.biometric_prompt_two_pane_medium_horizontal_guideline_padding
+ )
private lateinit var fingerprintRepository: FakeFingerprintPropertyRepository
private lateinit var promptRepository: FakePromptRepository
@@ -1370,6 +1391,142 @@
}
@Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun position_bottom_rotation0() = runGenericTest {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_0)
+ val position by collectLastValue(viewModel.position)
+ assertThat(position).isEqualTo(PromptPosition.Bottom)
+ } // TODO(b/335278136): Add test for no sensor landscape
+
+ @Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun position_bottom_forceLarge() = runGenericTest {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ viewModel.onSwitchToCredential()
+ val position by collectLastValue(viewModel.position)
+ assertThat(position).isEqualTo(PromptPosition.Bottom)
+ }
+
+ @Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun position_bottom_largeScreen() = runGenericTest {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ displayStateRepository.setIsLargeScreen(true)
+ val position by collectLastValue(viewModel.position)
+ assertThat(position).isEqualTo(PromptPosition.Bottom)
+ }
+
+ @Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun position_right_rotation90() = runGenericTest {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+ val position by collectLastValue(viewModel.position)
+ assertThat(position).isEqualTo(PromptPosition.Right)
+ }
+
+ @Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun position_left_rotation270() = runGenericTest {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ val position by collectLastValue(viewModel.position)
+ assertThat(position).isEqualTo(PromptPosition.Left)
+ }
+
+ @Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun position_top_rotation180() = runGenericTest {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ val position by collectLastValue(viewModel.position)
+ if (testCase.modalities.hasUdfps) {
+ assertThat(position).isEqualTo(PromptPosition.Top)
+ } else {
+ assertThat(position).isEqualTo(PromptPosition.Bottom)
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun guideline_bottom() = runGenericTest {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_0)
+ val guidelineBounds by collectLastValue(viewModel.guidelineBounds)
+ assertThat(guidelineBounds).isEqualTo(Rect(0, mediumTopGuidelinePadding, 0, 0))
+ } // TODO(b/335278136): Add test for no sensor landscape
+
+ @Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun guideline_right() = runGenericTest {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+
+ val isSmall = testCase.shouldStartAsImplicitFlow
+ val guidelineBounds by collectLastValue(viewModel.guidelineBounds)
+
+ if (isSmall) {
+ assertThat(guidelineBounds).isEqualTo(Rect(-smallHorizontalGuidelinePadding, 0, 0, 0))
+ } else if (testCase.modalities.hasUdfps) {
+ assertThat(guidelineBounds).isEqualTo(Rect(udfpsHorizontalGuidelinePadding, 0, 0, 0))
+ } else {
+ assertThat(guidelineBounds).isEqualTo(Rect(-mediumHorizontalGuidelinePadding, 0, 0, 0))
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun guideline_right_onlyShortTitle() =
+ runGenericTest(subtitle = "") {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+
+ val isSmall = testCase.shouldStartAsImplicitFlow
+ val guidelineBounds by collectLastValue(viewModel.guidelineBounds)
+
+ if (!isSmall && testCase.modalities.hasUdfps) {
+ assertThat(guidelineBounds)
+ .isEqualTo(Rect(-udfpsHorizontalShorterGuidelinePadding, 0, 0, 0))
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun guideline_left() = runGenericTest {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+
+ val isSmall = testCase.shouldStartAsImplicitFlow
+ val guidelineBounds by collectLastValue(viewModel.guidelineBounds)
+
+ if (isSmall) {
+ assertThat(guidelineBounds).isEqualTo(Rect(0, 0, -smallHorizontalGuidelinePadding, 0))
+ } else if (testCase.modalities.hasUdfps) {
+ assertThat(guidelineBounds).isEqualTo(Rect(0, 0, udfpsHorizontalGuidelinePadding, 0))
+ } else {
+ assertThat(guidelineBounds).isEqualTo(Rect(0, 0, -mediumHorizontalGuidelinePadding, 0))
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun guideline_left_onlyShortTitle() =
+ runGenericTest(subtitle = "") {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+
+ val isSmall = testCase.shouldStartAsImplicitFlow
+ val guidelineBounds by collectLastValue(viewModel.guidelineBounds)
+
+ if (!isSmall && testCase.modalities.hasUdfps) {
+ assertThat(guidelineBounds)
+ .isEqualTo(Rect(0, 0, -udfpsHorizontalShorterGuidelinePadding, 0))
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_CONSTRAINT_BP)
+ fun guideline_top() = runGenericTest {
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ val guidelineBounds by collectLastValue(viewModel.guidelineBounds)
+ if (testCase.modalities.hasUdfps) {
+ assertThat(guidelineBounds).isEqualTo(Rect(0, 0, 0, 0))
+ }
+ }
+
+ @Test
fun iconViewLoaded() = runGenericTest {
val isIconViewLoaded by collectLastValue(viewModel.isIconViewLoaded)
// TODO(b/328677869): Add test for noIcon logic.
@@ -1399,9 +1556,10 @@
private fun runGenericTest(
doNotStart: Boolean = false,
allowCredentialFallback: Boolean = false,
+ subtitle: String? = "s",
description: String? = null,
contentView: PromptContentView? = null,
- logoRes: Int = -1,
+ logoRes: Int = 0,
logoBitmap: Bitmap? = null,
logoDescription: String? = null,
packageName: String = OP_PACKAGE_NAME,
@@ -1437,11 +1595,11 @@
allowCredentialFallback = allowCredentialFallback,
fingerprint = testCase.fingerprint,
face = testCase.face,
+ subtitleFromApp = subtitle,
descriptionFromApp = description,
contentViewFromApp = contentView,
logoResFromApp = logoRes,
- logoBitmapFromApp =
- if (logoRes != -1) logoDrawableFromAppRes.toBitmap() else logoBitmap,
+ logoBitmapFromApp = if (logoRes != 0) logoDrawableFromAppRes.toBitmap() else logoBitmap,
logoDescriptionFromApp = logoDescription,
packageName = packageName,
)
@@ -1625,9 +1783,10 @@
face: FaceSensorPropertiesInternal? = null,
requireConfirmation: Boolean = false,
allowCredentialFallback: Boolean = false,
+ subtitleFromApp: String? = "s",
descriptionFromApp: String? = null,
contentViewFromApp: PromptContentView? = null,
- logoResFromApp: Int = -1,
+ logoResFromApp: Int = 0,
logoBitmapFromApp: Bitmap? = null,
logoDescriptionFromApp: String? = null,
packageName: String = OP_PACKAGE_NAME,
@@ -1636,7 +1795,7 @@
PromptInfo().apply {
logoDescription = logoDescriptionFromApp
title = "t"
- subtitle = "s"
+ subtitle = subtitleFromApp
description = descriptionFromApp
contentView = contentViewFromApp
authenticators = listOf(face, fingerprint).extractAuthenticatorTypes()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index ec02c64..411ff91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -113,8 +113,8 @@
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
mMediaDevices.add(mMediaDevice1);
mMediaDevices.add(mMediaDevice2);
- mMediaItems.add(new MediaItem(mMediaDevice1));
- mMediaItems.add(new MediaItem(mMediaDevice2));
+ mMediaItems.add(MediaItem.createDeviceMediaItem(mMediaDevice1));
+ mMediaItems.add(MediaItem.createDeviceMediaItem(mMediaDevice2));
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
mMediaOutputAdapter.updateItems();
@@ -146,7 +146,8 @@
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
- mMediaItems.add(new MediaItem());
+ mMediaItems.add(MediaItem.createPairNewDeviceMediaItem());
+ mMediaItems.add(MediaItem.createPairNewDeviceMediaItem());
mMediaOutputAdapter.updateItems();
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
@@ -589,7 +590,7 @@
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
- mMediaItems.add(new MediaItem());
+ mMediaItems.add(MediaItem.createPairNewDeviceMediaItem());
mMediaOutputAdapter.updateItems();
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
mViewHolder.mContainerLayout.performClick();
@@ -725,7 +726,7 @@
public void updateItems_controllerItemsUpdated_notUpdatesInAdapterUntilUpdateItems() {
mMediaOutputAdapter.updateItems();
List<MediaItem> updatedList = new ArrayList<>();
- updatedList.add(new MediaItem());
+ updatedList.add(MediaItem.createPairNewDeviceMediaItem());
when(mMediaOutputController.getMediaItemList()).thenReturn(updatedList);
assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaItems.size());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
index b7fefc0..c0d411b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
@@ -16,7 +16,9 @@
package com.android.systemui.mediaprojection.data.repository
+import android.media.projection.MediaProjectionInfo
import android.os.Binder
+import android.os.UserHandle
import android.view.ContentRecordingSession
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -26,6 +28,7 @@
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createTask
import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createToken
+import com.android.systemui.mediaprojection.taskswitcher.FakeMediaProjectionManager.Companion.createDisplaySession
import com.android.systemui.mediaprojection.taskswitcher.fakeActivityTaskManager
import com.android.systemui.mediaprojection.taskswitcher.fakeMediaProjectionManager
import com.android.systemui.mediaprojection.taskswitcher.taskSwitcherKosmos
@@ -33,6 +36,7 @@
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.verify
@RunWith(AndroidJUnit4::class)
@SmallTest
@@ -55,7 +59,8 @@
fakeActivityTaskManager.addRunningTasks(task)
repo.switchProjectedTask(task)
- assertThat(state).isEqualTo(MediaProjectionState.SingleTask(task))
+ assertThat(state).isInstanceOf(MediaProjectionState.Projecting.SingleTask::class.java)
+ assertThat((state as MediaProjectionState.Projecting.SingleTask).task).isEqualTo(task)
}
@Test
@@ -97,7 +102,7 @@
session = ContentRecordingSession.createDisplaySession(/* displayToMirror= */ 123)
)
- assertThat(state).isEqualTo(MediaProjectionState.EntireScreen)
+ assertThat(state).isInstanceOf(MediaProjectionState.Projecting.EntireScreen::class.java)
}
@Test
@@ -110,7 +115,27 @@
session = ContentRecordingSession.createTaskSession(taskWindowContainerToken)
)
- assertThat(state).isEqualTo(MediaProjectionState.EntireScreen)
+ assertThat(state).isInstanceOf(MediaProjectionState.Projecting.EntireScreen::class.java)
+ }
+
+ @Test
+ fun mediaProjectionState_entireScreen_hasHostPackage() =
+ testScope.runTest {
+ val state by collectLastValue(repo.mediaProjectionState)
+
+ val info =
+ MediaProjectionInfo(
+ /* packageName= */ "com.media.projection.repository.test",
+ /* handle= */ UserHandle.getUserHandleForUid(UserHandle.myUserId()),
+ /* launchCookie = */ null,
+ )
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ info = info,
+ session = createDisplaySession(),
+ )
+
+ assertThat((state as MediaProjectionState.Projecting.EntireScreen).hostPackage)
+ .isEqualTo("com.media.projection.repository.test")
}
@Test
@@ -125,6 +150,39 @@
session = ContentRecordingSession.createTaskSession(token.asBinder())
)
- assertThat(state).isEqualTo(MediaProjectionState.SingleTask(task))
+ assertThat(state).isInstanceOf(MediaProjectionState.Projecting.SingleTask::class.java)
+ assertThat((state as MediaProjectionState.Projecting.SingleTask).task).isEqualTo(task)
+ }
+
+ @Test
+ fun mediaProjectionState_singleTask_hasHostPackage() =
+ testScope.runTest {
+ val state by collectLastValue(repo.mediaProjectionState)
+
+ val token = createToken()
+ val task = createTask(taskId = 1, token = token)
+ fakeActivityTaskManager.addRunningTasks(task)
+
+ val info =
+ MediaProjectionInfo(
+ /* packageName= */ "com.media.projection.repository.test",
+ /* handle= */ UserHandle.getUserHandleForUid(UserHandle.myUserId()),
+ /* launchCookie = */ null,
+ )
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ info = info,
+ session = ContentRecordingSession.createTaskSession(token.asBinder())
+ )
+
+ assertThat((state as MediaProjectionState.Projecting.SingleTask).hostPackage)
+ .isEqualTo("com.media.projection.repository.test")
+ }
+
+ @Test
+ fun stopProjecting_invokesManager() =
+ testScope.runTest {
+ repo.stopProjecting()
+
+ verify(fakeMediaProjectionManager.mediaProjectionManager).stopActiveProjection()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
index b77a15b..61ea437 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
@@ -119,4 +119,12 @@
assertThat(lastModel).isEqualTo(isRecording)
}
+
+ @Test
+ fun stopRecording_invokesController() =
+ testScope.runTest {
+ underTest.stopRecording()
+
+ verify(recordingController).stopRecording()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractorTest.kt
new file mode 100644
index 0000000..abb6e2b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractorTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.domain.interactor
+
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor.Companion.createDialogLaunchOnClickListener
+import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import kotlin.test.Test
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+class OngoingActivityChipInteractorTest : SysuiTestCase() {
+ private val mockSystemUIDialog = mock<SystemUIDialog>()
+ private val dialogDelegate = SystemUIDialog.Delegate { mockSystemUIDialog }
+ private val dialogTransitionAnimator = mock<DialogTransitionAnimator>()
+
+ private val chipBackgroundView = mock<ChipBackgroundContainer>()
+ private val chipView =
+ mock<View>().apply {
+ whenever(
+ this.requireViewById<ChipBackgroundContainer>(
+ R.id.ongoing_activity_chip_background
+ )
+ )
+ .thenReturn(chipBackgroundView)
+ }
+
+ @Test
+ fun createDialogLaunchOnClickListener_showsDialogOnClick() {
+ val clickListener =
+ createDialogLaunchOnClickListener(dialogDelegate, dialogTransitionAnimator)
+
+ // Dialogs must be created on the main thread
+ context.mainExecutor.execute {
+ clickListener.onClick(chipView)
+ verify(dialogTransitionAnimator)
+ .showFromView(
+ eq(mockSystemUIDialog),
+ eq(chipBackgroundView),
+ eq(null),
+ anyBoolean(),
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
index 0f33b9d..a4505a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
@@ -16,8 +16,15 @@
package com.android.systemui.statusbar.chips.mediaprojection.domain.interactor
+import android.Manifest
+import android.content.Intent
+import android.content.packageManager
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.mockDialogTransitionAnimator
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
@@ -27,11 +34,24 @@
import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createTask
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
-import com.android.systemui.statusbar.chips.ui.viewmodel.mediaProjectionChipInteractor
+import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndCastToOtherDeviceDialogDelegate
+import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndShareToAppDialogDelegate
+import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mockito.doAnswer
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
@SmallTest
class MediaProjectionChipInteractorTest : SysuiTestCase() {
@@ -40,6 +60,30 @@
private val mediaProjectionRepo = kosmos.fakeMediaProjectionRepository
private val systemClock = kosmos.fakeSystemClock
+ private val mockCastDialog = mock<SystemUIDialog>()
+ private val mockShareDialog = mock<SystemUIDialog>()
+
+ private val chipBackgroundView = mock<ChipBackgroundContainer>()
+ private val chipView =
+ mock<View>().apply {
+ whenever(
+ this.requireViewById<ChipBackgroundContainer>(
+ R.id.ongoing_activity_chip_background
+ )
+ )
+ .thenReturn(chipBackgroundView)
+ }
+
+ @Before
+ fun setUp() {
+ setUpPackageManagerForMediaProjection(kosmos)
+
+ whenever(kosmos.mockSystemUIDialogFactory.create(any<EndCastToOtherDeviceDialogDelegate>()))
+ .thenReturn(mockCastDialog)
+ whenever(kosmos.mockSystemUIDialogFactory.create(any<EndShareToAppDialogDelegate>()))
+ .thenReturn(mockShareDialog)
+ }
+
private val underTest = kosmos.mediaProjectionChipInteractor
@Test
@@ -53,12 +97,15 @@
}
@Test
- fun chip_singleTaskState_isShownWithIcon() =
+ fun chip_singleTaskState_otherDevicesPackage_castToOtherDeviceChipShown() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
mediaProjectionRepo.mediaProjectionState.value =
- MediaProjectionState.SingleTask(createTask(taskId = 1))
+ MediaProjectionState.Projecting.SingleTask(
+ CAST_TO_OTHER_DEVICES_PACKAGE,
+ createTask(taskId = 1)
+ )
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon = (latest as OngoingActivityChipModel.Shown).icon
@@ -66,11 +113,12 @@
}
@Test
- fun chip_entireScreenState_isShownWithIcon() =
+ fun chip_entireScreenState_otherDevicesPackage_castToOtherDeviceChipShown() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
- mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(CAST_TO_OTHER_DEVICES_PACKAGE)
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon = (latest as OngoingActivityChipModel.Shown).icon
@@ -78,12 +126,39 @@
}
@Test
+ fun chip_singleTaskState_normalPackage_shareToAppChipShown() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.SingleTask(NORMAL_PACKAGE, createTask(taskId = 1))
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ val icon = (latest as OngoingActivityChipModel.Shown).icon
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenshot_share)
+ }
+
+ @Test
+ fun chip_entireScreenState_normalPackage_shareToAppChipShown() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ val icon = (latest as OngoingActivityChipModel.Shown).icon
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenshot_share)
+ }
+
+ @Test
fun chip_timeResetsOnEachNewShare() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
systemClock.setElapsedRealtime(1234)
- mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
assertThat((latest as OngoingActivityChipModel.Shown).startTimeMs).isEqualTo(1234)
@@ -92,9 +167,99 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
systemClock.setElapsedRealtime(5678)
- mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.SingleTask(
+ CAST_TO_OTHER_DEVICES_PACKAGE,
+ createTask(taskId = 1)
+ )
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
assertThat((latest as OngoingActivityChipModel.Shown).startTimeMs).isEqualTo(5678)
}
+
+ @Test
+ fun chip_castToOtherDevice_clickListenerShowsCastDialog() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(CAST_TO_OTHER_DEVICES_PACKAGE)
+
+ val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener)
+
+ // Dialogs must be created on the main thread
+ context.mainExecutor.execute {
+ clickListener.onClick(chipView)
+ verify(kosmos.mockDialogTransitionAnimator)
+ .showFromView(
+ eq(mockCastDialog),
+ eq(chipBackgroundView),
+ eq(null),
+ anyBoolean(),
+ )
+ }
+ }
+
+ @Test
+ fun chip_shareToApp_clickListenerShowsShareDialog() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
+
+ val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener)
+
+ // Dialogs must be created on the main thread
+ context.mainExecutor.execute {
+ clickListener.onClick(chipView)
+ verify(kosmos.mockDialogTransitionAnimator)
+ .showFromView(
+ eq(mockShareDialog),
+ eq(chipBackgroundView),
+ eq(null),
+ anyBoolean(),
+ )
+ }
+ }
+
+ companion object {
+ const val CAST_TO_OTHER_DEVICES_PACKAGE = "other.devices.package"
+ const val NORMAL_PACKAGE = "some.normal.package"
+
+ /**
+ * Sets up [kosmos.packageManager] so that [CAST_TO_OTHER_DEVICES_PACKAGE] is marked as a
+ * package that casts to other devices, and [NORMAL_PACKAGE] is *not* marked as casting to
+ * other devices.
+ */
+ fun setUpPackageManagerForMediaProjection(kosmos: Kosmos) {
+ kosmos.packageManager.apply {
+ whenever(
+ this.checkPermission(
+ Manifest.permission.REMOTE_DISPLAY_PROVIDER,
+ CAST_TO_OTHER_DEVICES_PACKAGE
+ )
+ )
+ .thenReturn(PackageManager.PERMISSION_GRANTED)
+ whenever(
+ this.checkPermission(
+ Manifest.permission.REMOTE_DISPLAY_PROVIDER,
+ NORMAL_PACKAGE
+ )
+ )
+ .thenReturn(PackageManager.PERMISSION_DENIED)
+
+ doAnswer {
+ // See Utils.isHeadlessRemoteDisplayProvider
+ if (
+ (it.arguments[0] as Intent).`package` == CAST_TO_OTHER_DEVICES_PACKAGE
+ ) {
+ emptyList()
+ } else {
+ listOf(mock<ResolveInfo>())
+ }
+ }
+ .whenever(this)
+ .queryIntentActivities(any(), anyInt())
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegateTest.kt
new file mode 100644
index 0000000..9a2f545
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegateTest.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.mediaprojection.ui.view
+
+import android.content.DialogInterface
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.mediaProjectionChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class EndCastToOtherDeviceDialogDelegateTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val sysuiDialog = mock<SystemUIDialog>()
+ private val sysuiDialogFactory = kosmos.mockSystemUIDialogFactory
+ private val underTest =
+ EndCastToOtherDeviceDialogDelegate(
+ sysuiDialogFactory,
+ kosmos.mediaProjectionChipInteractor,
+ )
+
+ @Before
+ fun setUp() {
+ whenever(sysuiDialogFactory.create(eq(underTest), eq(context))).thenReturn(sysuiDialog)
+ }
+
+ @Test
+ fun icon() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setIcon(R.drawable.ic_cast_connected)
+ }
+
+ @Test
+ fun title() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setTitle(R.string.cast_to_other_device_stop_dialog_title)
+ }
+
+ @Test
+ fun message() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setMessage(R.string.cast_to_other_device_stop_dialog_message)
+ }
+
+ @Test
+ fun negativeButton() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setNegativeButton(R.string.close_dialog_button, null)
+ }
+
+ @Test
+ fun positiveButton() =
+ kosmos.testScope.runTest {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ val clickListener = argumentCaptor<DialogInterface.OnClickListener>()
+
+ // Verify the button has the right text
+ verify(sysuiDialog)
+ .setPositiveButton(
+ eq(R.string.cast_to_other_device_stop_dialog_button),
+ clickListener.capture()
+ )
+
+ // Verify that clicking the button stops the recording
+ assertThat(kosmos.fakeMediaProjectionRepository.stopProjectingInvoked).isFalse()
+
+ clickListener.firstValue.onClick(mock<DialogInterface>(), 0)
+ runCurrent()
+
+ assertThat(kosmos.fakeMediaProjectionRepository.stopProjectingInvoked).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegateTest.kt
new file mode 100644
index 0000000..1d6e866
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegateTest.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.mediaprojection.ui.view
+
+import android.content.DialogInterface
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.mediaProjectionChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class EndShareToAppDialogDelegateTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val sysuiDialog = mock<SystemUIDialog>()
+ private val sysuiDialogFactory = kosmos.mockSystemUIDialogFactory
+ private val underTest =
+ EndShareToAppDialogDelegate(
+ sysuiDialogFactory,
+ kosmos.mediaProjectionChipInteractor,
+ )
+
+ @Before
+ fun setUp() {
+ whenever(sysuiDialogFactory.create(eq(underTest), eq(context))).thenReturn(sysuiDialog)
+ }
+
+ @Test
+ fun icon() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setIcon(R.drawable.ic_screenshot_share)
+ }
+
+ @Test
+ fun title() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setTitle(R.string.share_to_app_stop_dialog_title)
+ }
+
+ @Test
+ fun message() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setMessage(R.string.share_to_app_stop_dialog_message)
+ }
+
+ @Test
+ fun negativeButton() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setNegativeButton(R.string.close_dialog_button, null)
+ }
+
+ @Test
+ fun positiveButton() =
+ kosmos.testScope.runTest {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ val clickListener = argumentCaptor<DialogInterface.OnClickListener>()
+
+ // Verify the button has the right text
+ verify(sysuiDialog)
+ .setPositiveButton(
+ eq(R.string.share_to_app_stop_dialog_button),
+ clickListener.capture()
+ )
+
+ // Verify that clicking the button stops the recording
+ assertThat(kosmos.fakeMediaProjectionRepository.stopProjectingInvoked).isFalse()
+
+ clickListener.firstValue.onClick(mock<DialogInterface>(), 0)
+ runCurrent()
+
+ assertThat(kosmos.fakeMediaProjectionRepository.stopProjectingInvoked).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt
index 25efaf1..f6c3adb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt
@@ -16,8 +16,10 @@
package com.android.systemui.statusbar.chips.screenrecord.domain.interactor
+import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.mockDialogTransitionAnimator
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
@@ -26,11 +28,21 @@
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.chips.ui.viewmodel.screenRecordChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
@SmallTest
class ScreenRecordChipInteractorTest : SysuiTestCase() {
@@ -38,9 +50,27 @@
private val testScope = kosmos.testScope
private val screenRecordRepo = kosmos.screenRecordRepository
private val systemClock = kosmos.fakeSystemClock
+ private val mockSystemUIDialog = mock<SystemUIDialog>()
+
+ private val chipBackgroundView = mock<ChipBackgroundContainer>()
+ private val chipView =
+ mock<View>().apply {
+ whenever(
+ this.requireViewById<ChipBackgroundContainer>(
+ R.id.ongoing_activity_chip_background
+ )
+ )
+ .thenReturn(chipBackgroundView)
+ }
private val underTest = kosmos.screenRecordChipInteractor
+ @Before
+ fun setUp() {
+ whenever(kosmos.mockSystemUIDialogFactory.create(any<SystemUIDialog.Delegate>()))
+ .thenReturn(mockSystemUIDialog)
+ }
+
@Test
fun chip_doingNothingState_isHidden() =
testScope.runTest {
@@ -70,7 +100,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon = (latest as OngoingActivityChipModel.Shown).icon
- assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.stat_sys_screen_record)
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenrecord)
}
@Test
@@ -93,4 +123,25 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
assertThat((latest as OngoingActivityChipModel.Shown).startTimeMs).isEqualTo(5678)
}
+
+ @Test
+ fun chip_clickListenerShowsDialog() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+ screenRecordRepo.screenRecordState.value = ScreenRecordModel.Recording
+
+ val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener)
+
+ // Dialogs must be created on the main thread
+ context.mainExecutor.execute {
+ clickListener.onClick(chipView)
+ verify(kosmos.mockDialogTransitionAnimator)
+ .showFromView(
+ eq(mockSystemUIDialog),
+ eq(chipBackgroundView),
+ eq(null),
+ anyBoolean(),
+ )
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegateTest.kt
new file mode 100644
index 0000000..bca6763
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegateTest.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.screenrecord.ui.view
+
+import android.content.DialogInterface
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.screenrecord.data.repository.screenRecordRepository
+import com.android.systemui.statusbar.chips.ui.viewmodel.screenRecordChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class EndScreenRecordingDialogDelegateTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+
+ private val sysuiDialog = mock<SystemUIDialog>()
+ private val sysuiDialogFactory = kosmos.mockSystemUIDialogFactory
+
+ private val underTest =
+ EndScreenRecordingDialogDelegate(
+ sysuiDialogFactory,
+ kosmos.screenRecordChipInteractor,
+ )
+
+ @Before
+ fun setUp() {
+ whenever(sysuiDialogFactory.create(eq(underTest), eq(context))).thenReturn(sysuiDialog)
+ }
+
+ @Test
+ fun icon() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setIcon(R.drawable.ic_screenrecord)
+ }
+
+ @Test
+ fun title() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setTitle(R.string.screenrecord_stop_dialog_title)
+ }
+
+ @Test
+ fun message() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setMessage(R.string.screenrecord_stop_dialog_message)
+ }
+
+ @Test
+ fun negativeButton() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setNegativeButton(R.string.close_dialog_button, null)
+ }
+
+ @Test
+ fun positiveButton() =
+ kosmos.testScope.runTest {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ val clickListener = argumentCaptor<DialogInterface.OnClickListener>()
+
+ // Verify the button has the right text
+ verify(sysuiDialog)
+ .setPositiveButton(
+ eq(R.string.screenrecord_stop_dialog_button),
+ clickListener.capture()
+ )
+
+ // Verify that clicking the button stops the recording
+ assertThat(kosmos.screenRecordRepository.stopRecordingInvoked).isFalse()
+
+ clickListener.firstValue.onClick(mock<DialogInterface>(), 0)
+ runCurrent()
+
+ assertThat(kosmos.screenRecordRepository.stopRecordingInvoked).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index 121229c..6712963 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -30,8 +30,11 @@
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
@SmallTest
@@ -46,6 +49,11 @@
private val underTest = kosmos.ongoingActivityChipsViewModel
+ @Before
+ fun setUp() {
+ setUpPackageManagerForMediaProjection(kosmos)
+ }
+
@Test
fun chip_allHidden_hidden() =
testScope.runTest {
@@ -91,7 +99,8 @@
fun chip_screenRecordShowAndMediaProjectionShow_screenRecordShown() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.Recording
- mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
callState.value = OngoingActivityChipModel.Hidden
val latest by collectLastValue(underTest.chip)
@@ -103,7 +112,8 @@
fun chip_mediaProjectionShowAndCallShow_mediaProjectionShown() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.DoingNothing
- mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
val callChip =
OngoingActivityChipModel.Shown(
Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
@@ -113,7 +123,7 @@
val latest by collectLastValue(underTest.chip)
- assertIsMediaProjectionChip(latest)
+ assertIsShareToAppChip(latest)
}
@Test
@@ -152,10 +162,14 @@
assertThat(latest).isEqualTo(callChip)
// WHEN the higher priority media projection chip is added
- mediaProjectionState.value = MediaProjectionState.SingleTask(createTask(taskId = 1))
+ mediaProjectionState.value =
+ MediaProjectionState.Projecting.SingleTask(
+ NORMAL_PACKAGE,
+ createTask(taskId = 1),
+ )
// THEN the higher priority media projection chip is used
- assertIsMediaProjectionChip(latest)
+ assertIsShareToAppChip(latest)
// WHEN the higher priority screen record chip is added
screenRecordState.value = ScreenRecordModel.Recording
@@ -169,7 +183,8 @@
testScope.runTest {
// WHEN all chips are active
screenRecordState.value = ScreenRecordModel.Recording
- mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
val callChip =
OngoingActivityChipModel.Shown(
@@ -187,7 +202,7 @@
screenRecordState.value = ScreenRecordModel.DoingNothing
// THEN the lower priority media projection is used
- assertIsMediaProjectionChip(latest)
+ assertIsShareToAppChip(latest)
// WHEN the higher priority media projection is removed
mediaProjectionState.value = MediaProjectionState.NotProjecting
@@ -200,13 +215,13 @@
fun assertIsScreenRecordChip(latest: OngoingActivityChipModel?) {
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon = (latest as OngoingActivityChipModel.Shown).icon
- assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.stat_sys_screen_record)
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenrecord)
}
- fun assertIsMediaProjectionChip(latest: OngoingActivityChipModel?) {
+ fun assertIsShareToAppChip(latest: OngoingActivityChipModel?) {
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon = (latest as OngoingActivityChipModel.Shown).icon
- assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_cast_connected)
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenshot_share)
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index c9fe449..cdb2b88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -37,8 +37,10 @@
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
-import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsMediaProjectionChip
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsScreenRecordChip
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsShareToAppChip
import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
import com.android.systemui.statusbar.data.model.StatusBarMode
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID
@@ -55,6 +57,7 @@
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
@SmallTest
@@ -77,6 +80,11 @@
kosmos.applicationCoroutineScope,
)
+ @Before
+ fun setUp() {
+ setUpPackageManagerForMediaProjection(kosmos)
+ }
+
@Test
fun isTransitioningFromLockscreenToOccluded_started_isTrue() =
testScope.runTest {
@@ -405,9 +413,9 @@
assertThat(latest).isEqualTo(OngoingActivityChipModel.Hidden)
kosmos.fakeMediaProjectionRepository.mediaProjectionState.value =
- MediaProjectionState.EntireScreen
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
- assertIsMediaProjectionChip(latest)
+ assertIsShareToAppChip(latest)
}
private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) =
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt
index 62e56be..976a19c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt
@@ -20,6 +20,7 @@
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
val Kosmos.dialogTransitionAnimator by Fixture {
fakeDialogTransitionAnimator(
@@ -29,3 +30,5 @@
interactionJankMonitor = interactionJankMonitor,
)
}
+
+val Kosmos.mockDialogTransitionAnimator by Fixture { mock<DialogTransitionAnimator>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
index 6d46694..3c62b44 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
@@ -22,6 +22,7 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.notificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
import com.android.systemui.statusbar.ui.systemBarUtilsProxy
@@ -30,6 +31,7 @@
KeyguardClockViewModel(
keyguardClockInteractor = keyguardClockInteractor,
applicationScope = applicationCoroutineScope,
+ aodNotificationIconViewModel = notificationIconContainerAlwaysOnDisplayViewModel,
notifsKeyguardInteractor = notificationsKeyguardInteractor,
shadeInteractor = shadeInteractor,
systemBarUtils = systemBarUtilsProxy,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
index c4365c9..d631f92 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
@@ -25,4 +25,10 @@
override val mediaProjectionState: MutableStateFlow<MediaProjectionState> =
MutableStateFlow(MediaProjectionState.NotProjecting)
+
+ var stopProjectingInvoked = false
+
+ override suspend fun stopProjecting() {
+ stopProjectingInvoked = true
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
index fb0e368..30b4763 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
@@ -22,4 +22,10 @@
class FakeScreenRecordRepository : ScreenRecordRepository {
override val screenRecordState: MutableStateFlow<ScreenRecordModel> =
MutableStateFlow(ScreenRecordModel.DoingNothing)
+
+ var stopRecordingInvoked = false
+
+ override suspend fun stopRecording() {
+ stopRecordingInvoked = true
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorKosmos.kt
new file mode 100644
index 0000000..062b448
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorKosmos.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.mediaprojection.domain.interactor
+
+import android.content.packageManager
+import com.android.systemui.animation.mockDialogTransitionAnimator
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
+import com.android.systemui.util.time.fakeSystemClock
+
+val Kosmos.mediaProjectionChipInteractor: MediaProjectionChipInteractor by
+ Kosmos.Fixture {
+ MediaProjectionChipInteractor(
+ scope = applicationCoroutineScope,
+ mediaProjectionRepository = fakeMediaProjectionRepository,
+ packageManager = packageManager,
+ systemClock = fakeSystemClock,
+ dialogFactory = mockSystemUIDialogFactory,
+ dialogTransitionAnimator = mockDialogTransitionAnimator,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
index 88bde2e..51ec540 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
@@ -16,13 +16,14 @@
package com.android.systemui.statusbar.chips.ui.viewmodel
+import com.android.systemui.animation.mockDialogTransitionAnimator
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
-import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
-import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.mediaProjectionChipInteractor
import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
import com.android.systemui.util.time.fakeSystemClock
val Kosmos.screenRecordChipInteractor: ScreenRecordChipInteractor by
@@ -30,15 +31,8 @@
ScreenRecordChipInteractor(
scope = applicationCoroutineScope,
screenRecordRepository = screenRecordRepository,
- systemClock = fakeSystemClock,
- )
- }
-
-val Kosmos.mediaProjectionChipInteractor: MediaProjectionChipInteractor by
- Kosmos.Fixture {
- MediaProjectionChipInteractor(
- scope = applicationCoroutineScope,
- mediaProjectionRepository = fakeMediaProjectionRepository,
+ dialogFactory = mockSystemUIDialogFactory,
+ dialogTransitionAnimator = mockDialogTransitionAnimator,
systemClock = fakeSystemClock,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryKosmos.kt
index 3bb9580..1851c89 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryKosmos.kt
@@ -21,8 +21,9 @@
import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.model.sysUiState
+import com.android.systemui.util.mockito.mock
-val Kosmos.systemUIDialogFactory by
+val Kosmos.systemUIDialogFactory: SystemUIDialogFactory by
Kosmos.Fixture {
SystemUIDialogFactory(
applicationContext,
@@ -32,3 +33,6 @@
dialogTransitionAnimator,
)
}
+
+val Kosmos.mockSystemUIDialogFactory: SystemUIDialog.Factory by
+ Kosmos.Fixture { mock<SystemUIDialog.Factory>() }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 6fc05b7..eae516e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -2003,7 +2003,7 @@
final AutofillManagerServiceImpl service =
peekServiceForUserWithLocalBinderIdentityLocked(userId);
if (service != null) {
- service.setViewAutofilled(sessionId, getCallingUid(), id);
+ service.setViewAutofilledLocked(sessionId, getCallingUid(), id);
} else if (sVerbose) {
Slog.v(TAG, "setAutofillFailure(): no service for " + userId);
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 588266f..9ad15b2 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -478,7 +478,7 @@
}
@GuardedBy("mLock")
- void setViewAutofilled(int sessionId, int uid, @NonNull AutofillId id) {
+ void setViewAutofilledLocked(int sessionId, int uid, @NonNull AutofillId id) {
if (!isEnabledLocked()) {
Slog.wtf(TAG, "Service not enabled");
return;
@@ -488,7 +488,7 @@
Slog.v(TAG, "setViewAutofilled(): no session for " + sessionId + "(" + uid + ")");
return;
}
- session.setViewAutofilled(id);
+ session.setViewAutofilledLocked(id);
}
@GuardedBy("mLock")
@@ -792,10 +792,9 @@
* Initializes the last fill selection after an autofill service returned a new
* {@link FillResponse}.
*/
- void setLastResponse(int sessionId, @NonNull FillResponse response) {
- synchronized (mLock) {
+ @GuardedBy("mLock")
+ void setLastResponseLocked(int sessionId, @NonNull FillResponse response) {
mEventHistory = new FillEventHistory(sessionId, response.getClientState());
- }
}
void setLastAugmentedAutofillResponse(int sessionId) {
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
index aa76200..435a671 100644
--- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -675,7 +675,14 @@
} else if (autofillIds.contains(autofillId)) {
if (sVerbose) {
Slog.v(TAG, "Logging autofill for id:" + autofillId);
- event.mViewFillSuccessCount++;
+ }
+ event.mViewFillSuccessCount++;
+ autofillIds.remove(autofillId);
+ event.mAlreadyFilledAutofillIds.add(autofillId);
+ } else if (event.mAlreadyFilledAutofillIds.contains(autofillId)) {
+ if (sVerbose) {
+ Slog.v(TAG, "Successfully filled autofillId:" + autofillId
+ + " already processed ");
}
} else {
Slog.w(TAG, "Successfully filled autofillId:" + autofillId
@@ -850,6 +857,7 @@
int mViewFilledButUnexpectedCount = 0;
ArraySet<AutofillId> mAutofillIdsAttemptedAutofill;
+ ArraySet<AutofillId> mAlreadyFilledAutofillIds = new ArraySet<>();
PresentationStatsEventInternal() {}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index aa67ffe..ecb0ad8 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1677,22 +1677,23 @@
final LogMaker requestLog;
- // Start a new FillResponse logger for the success case.
- mFillResponseEventLogger.startLogForNewResponse();
- mFillResponseEventLogger.maybeSetRequestId(requestId);
- mFillResponseEventLogger.maybeSetAppPackageUid(uid);
- mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SUCCESS);
- mFillResponseEventLogger.startResponseProcessingTime();
- // Time passed since session was created
- final long fillRequestReceivedRelativeTimestamp =
- SystemClock.elapsedRealtime() - mLatencyBaseTime;
- mPresentationStatsEventLogger.maybeSetFillResponseReceivedTimestampMs(
- (int) (fillRequestReceivedRelativeTimestamp));
- mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis(
- (int) (fillRequestReceivedRelativeTimestamp));
- mFillResponseEventLogger.maybeSetDetectionPreference(getDetectionPreferenceForLogging());
-
synchronized (mLock) {
+ // Start a new FillResponse logger for the success case.
+ mFillResponseEventLogger.startLogForNewResponse();
+ mFillResponseEventLogger.maybeSetRequestId(requestId);
+ mFillResponseEventLogger.maybeSetAppPackageUid(uid);
+ mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SUCCESS);
+ mFillResponseEventLogger.startResponseProcessingTime();
+ // Time passed since session was created
+ final long fillRequestReceivedRelativeTimestamp =
+ SystemClock.elapsedRealtime() - mLatencyBaseTime;
+ mPresentationStatsEventLogger.maybeSetFillResponseReceivedTimestampMs(
+ (int) (fillRequestReceivedRelativeTimestamp));
+ mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis(
+ (int) (fillRequestReceivedRelativeTimestamp));
+ mFillResponseEventLogger.maybeSetDetectionPreference(
+ getDetectionPreferenceForLogging());
+
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: "
+ id + " destroyed");
@@ -1744,11 +1745,9 @@
Slog.v(TAG, "Service requested to wait for delayed fill response.");
registerDelayedFillBroadcastLocked();
}
- }
- mService.setLastResponse(id, response);
+ mService.setLastResponseLocked(id, response);
- synchronized (mLock) {
if (mLogViewEntered) {
mLogViewEntered = false;
mService.logViewEntered(id, null);
@@ -1821,16 +1820,18 @@
}
int datasetCount = (datasetList == null) ? 0 : datasetList.size();
- mFillResponseEventLogger.maybeSetTotalDatasetsProvided(datasetCount);
- // It's possible that this maybe overwritten later on after PCC filtering.
- mFillResponseEventLogger.maybeSetAvailableCount(datasetCount);
+ synchronized (mLock) {
+ mFillResponseEventLogger.maybeSetTotalDatasetsProvided(datasetCount);
+ // It's possible that this maybe overwritten later on after PCC filtering.
+ mFillResponseEventLogger.maybeSetAvailableCount(datasetCount);
- // TODO(b/266379948): Ideally wait for PCC request to finish for a while more
- // (say 100ms) before proceeding further on.
+ // TODO(b/266379948): Ideally wait for PCC request to finish for a while more
+ // (say 100ms) before proceeding further on.
- processResponseLockedForPcc(response, response.getClientState(), requestFlags);
- mFillResponseEventLogger.maybeSetLatencyResponseProcessingMillis();
- mFillResponseEventLogger.logAndEndEvent();
+ processResponseLockedForPcc(response, response.getClientState(), requestFlags);
+ mFillResponseEventLogger.maybeSetLatencyResponseProcessingMillis();
+ mFillResponseEventLogger.logAndEndEvent();
+ }
}
@@ -2381,21 +2382,22 @@
@Nullable CharSequence message) {
boolean showMessage = !TextUtils.isEmpty(message);
- // Start a new FillResponse logger for the failure or timeout case.
- mFillResponseEventLogger.startLogForNewResponse();
- mFillResponseEventLogger.maybeSetRequestId(requestId);
- mFillResponseEventLogger.maybeSetAppPackageUid(uid);
- mFillResponseEventLogger.maybeSetAvailableCount(
- AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT);
- mFillResponseEventLogger.maybeSetTotalDatasetsProvided(
- AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT);
- mFillResponseEventLogger.maybeSetDetectionPreference(getDetectionPreferenceForLogging());
- final long fillRequestReceivedRelativeTimestamp =
- SystemClock.elapsedRealtime() - mLatencyBaseTime;
- mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis(
- (int)(fillRequestReceivedRelativeTimestamp));
-
synchronized (mLock) {
+ // Start a new FillResponse logger for the failure or timeout case.
+ mFillResponseEventLogger.startLogForNewResponse();
+ mFillResponseEventLogger.maybeSetRequestId(requestId);
+ mFillResponseEventLogger.maybeSetAppPackageUid(uid);
+ mFillResponseEventLogger.maybeSetAvailableCount(
+ AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT);
+ mFillResponseEventLogger.maybeSetTotalDatasetsProvided(
+ AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT);
+ mFillResponseEventLogger.maybeSetDetectionPreference(
+ getDetectionPreferenceForLogging());
+ final long fillRequestReceivedRelativeTimestamp =
+ SystemClock.elapsedRealtime() - mLatencyBaseTime;
+ mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis(
+ (int) (fillRequestReceivedRelativeTimestamp));
+
unregisterDelayedFillBroadcastLocked();
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onFillRequestFailureOrTimeout(req=" + requestId
@@ -2635,8 +2637,8 @@
+ id + " destroyed");
return;
}
+ mSaveEventLogger.maybeSetLatencySaveRequestMillis();
}
- mSaveEventLogger.maybeSetLatencySaveRequestMillis();
mHandler.sendMessage(obtainMessage(
AutofillManagerServiceImpl::handleSessionSave,
mService, this));
@@ -3215,6 +3217,58 @@
return saveInfo == null ? 0 : saveInfo.getFlags();
}
+ static class SaveInfoStats {
+ public int saveInfoCount;
+ public int saveDataTypeCount;
+ }
+
+ /**
+ * Get statistic information of save info in current session. Specifically
+ * 1. how many save info the current session has.
+ * 2. How many distinct save data types current session has.
+ *
+ * @return SaveInfoStats returns the above two number in a SaveInfoStats object
+ */
+ @GuardedBy("mLock")
+ private SaveInfoStats getSaveInfoStatsLocked() {
+ SaveInfoStats retSaveInfoStats = new SaveInfoStats();
+ retSaveInfoStats.saveInfoCount = -1;
+ retSaveInfoStats.saveDataTypeCount = -1;
+
+ if (mContexts == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "getSaveInfoStatsLocked(): mContexts is null");
+ }
+ } else if (mResponses == null) {
+ // Happens when the activity / session was finished before the service replied, or
+ // when the service cannot autofill it (and returned a null response).
+ if (sVerbose) {
+ Slog.v(TAG, "getSaveInfoStatsLocked(): mResponses is null");
+ }
+ return retSaveInfoStats;
+ } else {
+ int numSaveInfos = 0;
+ int numSaveDataTypes = 0;
+ ArraySet<Integer> saveDataTypeSeen = new ArraySet<>();
+ final int numResponses = mResponses.size();
+ for (int responseNum = 0; responseNum < numResponses; responseNum++) {
+ final FillResponse response = mResponses.valueAt(responseNum);
+ if (response != null && response.getSaveInfo() != null) {
+ numSaveInfos += 1;
+ int saveDataType = response.getSaveInfo().getType();
+ if (!saveDataTypeSeen.contains(saveDataType)) {
+ saveDataTypeSeen.add(saveDataType);
+ numSaveDataTypes += 1;
+ }
+ }
+ }
+ retSaveInfoStats.saveInfoCount = numSaveInfos;
+ retSaveInfoStats.saveDataTypeCount = numSaveDataTypes;
+ }
+
+ return retSaveInfoStats;
+ }
+
/**
* Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_CONTEXT_COMMITTED}
* when necessary.
@@ -3227,7 +3281,9 @@
mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this,
Event.NO_SAVE_UI_REASON_NONE,
COMMIT_REASON_UNKNOWN));
- logAllEvents(COMMIT_REASON_UNKNOWN);
+ synchronized (mLock) {
+ logAllEventsLocked(COMMIT_REASON_UNKNOWN);
+ }
}
/**
@@ -3251,6 +3307,11 @@
mSessionCommittedEventLogger.maybeSetCommitReason(commitReason);
mSessionCommittedEventLogger.maybeSetRequestCount(mRequestCount);
+ SaveInfoStats saveInfoStats = getSaveInfoStatsLocked();
+ mSessionCommittedEventLogger.maybeSetSaveInfoCount(saveInfoStats.saveInfoCount);
+ mSessionCommittedEventLogger.maybeSetSaveDataTypeCount(saveInfoStats.saveDataTypeCount);
+ mSessionCommittedEventLogger.maybeSetLastFillResponseHasSaveInfo(
+ getSaveInfoLocked() != null);
mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NONE);
}
@@ -4571,7 +4632,7 @@
FillResponse response = viewState.getSecondaryResponse();
if (response != null) {
- logPresentationStatsOnViewEntered(response, isCredmanRequested);
+ logPresentationStatsOnViewEnteredLocked(response, isCredmanRequested);
}
// If the ViewState is ready to be displayed, onReady() will be called.
@@ -4662,7 +4723,7 @@
FillResponse response = viewState.getResponse();
if (response != null) {
- logPresentationStatsOnViewEntered(response, isCredmanRequested);
+ logPresentationStatsOnViewEnteredLocked(response, isCredmanRequested);
}
if (isSameViewEntered) {
@@ -4703,7 +4764,7 @@
}
@GuardedBy("mLock")
- private void logPresentationStatsOnViewEntered(FillResponse response,
+ private void logPresentationStatsOnViewEnteredLocked(FillResponse response,
boolean isCredmanRequested) {
mPresentationStatsEventLogger.maybeSetRequestId(response.getRequestId());
mPresentationStatsEventLogger.maybeSetIsCredentialRequest(isCredmanRequested);
@@ -5061,7 +5122,7 @@
getUiForShowing().showFillDialog(filledId, response, filterText,
mService.getServicePackageName(), mComponentName, serviceIcon, this,
- id, mCompatMode, mPresentationStatsEventLogger);
+ id, mCompatMode, mPresentationStatsEventLogger, mLock);
return true;
}
@@ -5420,7 +5481,7 @@
* Sets the state of views that failed to autofill.
*/
@GuardedBy("mLock")
- void setViewAutofilled(@NonNull AutofillId id) {
+ void setViewAutofilledLocked(@NonNull AutofillId id) {
if (sVerbose) {
Slog.v(TAG, "View autofilled: " + id);
}
@@ -6663,7 +6724,7 @@
}
@GuardedBy("mLock")
- private void logAllEvents(@AutofillCommitReason int val) {
+ private void logAllEventsLocked(@AutofillCommitReason int val) {
if (sVerbose) {
Slog.v(TAG, "logAllEvents(" + id + "): commitReason: " + val);
}
@@ -6695,7 +6756,7 @@
if (sVerbose) {
Slog.v(TAG, "destroyLocked for session: " + id);
}
- logAllEvents(COMMIT_REASON_SESSION_DESTROYED);
+ logAllEventsLocked(COMMIT_REASON_SESSION_DESTROYED);
if (mDestroyed) {
return null;
diff --git a/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java b/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java
index 1be8548..8f3c880 100644
--- a/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java
@@ -94,6 +94,33 @@
}
/**
+ * Set how many save infos there are in current session as long as mEventInternal presents.
+ */
+ public void maybeSetSaveInfoCount(int saveInfoCount) {
+ mEventInternal.ifPresent(event -> {
+ event.mSaveInfoCount = saveInfoCount;
+ });
+ }
+
+ /**
+ * Set how many save data types there are in current session as long as mEventInternal presents.
+ */
+ public void maybeSetSaveDataTypeCount(int saveDataTypeCount) {
+ mEventInternal.ifPresent(event -> {
+ event.mSaveDataTypeCount = saveDataTypeCount;
+ });
+ }
+
+ /**
+ * Set whether last fill response in session has save info as long as mEventInternal presents.
+ */
+ public void maybeSetLastFillResponseHasSaveInfo(boolean lastFillResponseHasSaveInfo) {
+ mEventInternal.ifPresent(event -> {
+ event.mLastFillResponseHasSaveInfo = lastFillResponseHasSaveInfo;
+ });
+ }
+
+ /**
* Log an AUTOFILL_SESSION_COMMITTED event.
*/
public void logAndEndEvent() {
@@ -109,7 +136,10 @@
+ " mRequestCount=" + event.mRequestCount
+ " mCommitReason=" + event.mCommitReason
+ " mSessionDurationMillis=" + event.mSessionDurationMillis
- + " mServiceUid=" + event.mServiceUid);
+ + " mServiceUid=" + event.mServiceUid
+ + " mSaveInfoCount=" + event.mSaveInfoCount
+ + " mSaveDataTypeCount=" + event.mSaveDataTypeCount
+ + " mLastFillResponseHasSaveInfo=" + event.mLastFillResponseHasSaveInfo);
}
FrameworkStatsLog.write(
AUTOFILL_SESSION_COMMITTED,
@@ -118,7 +148,10 @@
event.mRequestCount,
event.mCommitReason,
event.mSessionDurationMillis,
- event.mServiceUid);
+ event.mServiceUid,
+ event.mSaveInfoCount,
+ event.mSaveDataTypeCount,
+ event.mLastFillResponseHasSaveInfo);
mEventInternal = Optional.empty();
}
@@ -127,6 +160,9 @@
int mRequestCount = 0;
int mCommitReason = COMMIT_REASON_UNKNOWN;
long mSessionDurationMillis = 0;
+ int mSaveInfoCount = -1;
+ int mSaveDataTypeCount = -1;
+ boolean mLastFillResponseHasSaveInfo = false;
int mServiceUid = -1;
SessionCommittedEventInternal() {
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 3b9c54f..8cc666b 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -425,7 +425,8 @@
@Nullable String filterText, @Nullable String servicePackageName,
@NonNull ComponentName componentName, @Nullable Drawable serviceIcon,
@NonNull AutoFillUiCallback callback, int sessionId, boolean compatMode,
- @Nullable PresentationStatsEventLogger mPresentationStatsEventLogger) {
+ @Nullable PresentationStatsEventLogger presentationStatsEventLogger,
+ @NonNull Object sessionLock) {
if (sVerbose) {
Slog.v(TAG, "showFillDialog for "
+ componentName.toShortString() + ": " + response);
@@ -467,9 +468,11 @@
@Override
public void onDatasetPicked(Dataset dataset) {
log(MetricsEvent.TYPE_ACTION);
- if (mPresentationStatsEventLogger != null) {
- mPresentationStatsEventLogger.maybeSetPositiveCtaButtonClicked(
- true);
+ synchronized (sessionLock) {
+ if (presentationStatsEventLogger != null) {
+ presentationStatsEventLogger.maybeSetPositiveCtaButtonClicked(
+ true);
+ }
}
hideFillDialogUiThread(callback);
if (mCallback != null) {
@@ -482,8 +485,10 @@
@Override
public void onDismissed() {
log(MetricsEvent.TYPE_DISMISS);
- if (mPresentationStatsEventLogger != null) {
- mPresentationStatsEventLogger.maybeSetDialogDismissed(true);
+ synchronized (sessionLock) {
+ if (presentationStatsEventLogger != null) {
+ presentationStatsEventLogger.maybeSetDialogDismissed(true);
+ }
}
hideFillDialogUiThread(callback);
callback.requestShowSoftInput(focusedId);
@@ -493,9 +498,11 @@
@Override
public void onCanceled() {
log(MetricsEvent.TYPE_CLOSE);
- if (mPresentationStatsEventLogger != null) {
- mPresentationStatsEventLogger.maybeSetNegativeCtaButtonClicked(
- true);
+ synchronized (sessionLock) {
+ if (presentationStatsEventLogger != null) {
+ presentationStatsEventLogger.maybeSetNegativeCtaButtonClicked(
+ true);
+ }
}
hideFillDialogUiThread(callback);
callback.requestShowSoftInput(focusedId);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index c9cce15..0ab6bbc 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -532,7 +532,8 @@
String packageName, int userId) {
startObservingDevicePresence_enforcePermission();
- mDevicePresenceProcessor.startObservingDevicePresence(request, packageName, userId);
+ mDevicePresenceProcessor.startObservingDevicePresence(
+ request, packageName, userId, /* enforcePermissions */ true);
}
@Override
@@ -541,7 +542,8 @@
String packageName, int userId) {
stopObservingDevicePresence_enforcePermission();
- mDevicePresenceProcessor.stopObservingDevicePresence(request, packageName, userId);
+ mDevicePresenceProcessor.stopObservingDevicePresence(
+ request, packageName, userId, /* enforcePermissions */ true);
}
@Override
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index c892b84..3d53deb 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -21,6 +21,7 @@
import android.companion.AssociationInfo;
import android.companion.ContextSyncMessage;
import android.companion.Flags;
+import android.companion.ObservingDevicePresenceRequest;
import android.companion.Telecom;
import android.companion.datatransfer.PermissionSyncRequest;
import android.net.MacAddress;
@@ -193,6 +194,43 @@
break;
}
+ case "start-observing-device-presence-uuid": {
+ if (Flags.devicePresence()) {
+ int userId = getNextIntArgRequired();
+ String packageName = getNextArgRequired();
+ String uuid = getNextArgRequired();
+ if ("null".equals(uuid)) {
+ out.println("UUID can not be null.");
+ break;
+ }
+ ParcelUuid parcelUuid = ParcelUuid.fromString(uuid);
+ ObservingDevicePresenceRequest request = new ObservingDevicePresenceRequest
+ .Builder().setUuid(parcelUuid).build();
+ mDevicePresenceProcessor.startObservingDevicePresence(
+ request, packageName, userId, /* enforcePermissions */ false);
+
+ }
+ break;
+ }
+
+ case "stop-observing-device-presence-uuid": {
+ if (Flags.devicePresence()) {
+ int userId = getNextIntArgRequired();
+ String packageName = getNextArgRequired();
+ String uuid = getNextArgRequired();
+ if ("null".equals(uuid)) {
+ out.println("UUID can not be null.");
+ break;
+ }
+ ParcelUuid parcelUuid = ParcelUuid.fromString(uuid);
+ ObservingDevicePresenceRequest request = new ObservingDevicePresenceRequest
+ .Builder().setUuid(parcelUuid).build();
+ mDevicePresenceProcessor.stopObservingDevicePresence(
+ request, packageName, userId, /* enforcePermissions */ false);
+ }
+ break;
+ }
+
case "get-backup-payload": {
final int userId = getNextIntArgRequired();
byte[] payload = mBackupRestoreProcessor.getBackupPayload(userId);
@@ -515,6 +553,14 @@
pw.println(" callback after simulate-device-event-device-locked");
pw.println(" command has been called.");
pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+
+ pw.println(" start-observing-device-presence-uuid USER_ID PACKAGE_NAME UUID");
+ pw.println(" Start observing device presence base on the UUID.");
+ pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+
+ pw.println(" stop-observing-device-presence-uuid USER_ID PACKAGE_NAME UUID");
+ pw.println(" Stop observing device presence base on the UUID.");
+ pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
}
pw.println(" remove-inactive-associations");
diff --git a/services/companion/java/com/android/server/companion/devicepresence/DevicePresenceProcessor.java b/services/companion/java/com/android/server/companion/devicepresence/DevicePresenceProcessor.java
index af49df6..a374d27 100644
--- a/services/companion/java/com/android/server/companion/devicepresence/DevicePresenceProcessor.java
+++ b/services/companion/java/com/android/server/companion/devicepresence/DevicePresenceProcessor.java
@@ -181,14 +181,16 @@
* Process device presence start request.
*/
public void startObservingDevicePresence(ObservingDevicePresenceRequest request,
- String packageName, int userId) {
+ String packageName, int userId, boolean enforcePermissions) {
Slog.i(TAG,
"Start observing request=[" + request + "] for userId=[" + userId + "], package=["
+ packageName + "]...");
final ParcelUuid requestUuid = request.getUuid();
if (requestUuid != null) {
- enforceCallerCanObserveDevicePresenceByUuid(mContext);
+ if (enforcePermissions) {
+ enforceCallerCanObserveDevicePresenceByUuid(mContext, packageName, userId);
+ }
// If it's already being observed, then no-op.
if (mObservableUuidStore.isUuidBeingObserved(requestUuid, userId, packageName)) {
@@ -236,7 +238,7 @@
* Process device presence stop request.
*/
public void stopObservingDevicePresence(ObservingDevicePresenceRequest request,
- String packageName, int userId) {
+ String packageName, int userId, boolean enforcePermissions) {
Slog.i(TAG,
"Stop observing request=[" + request + "] for userId=[" + userId + "], package=["
+ packageName + "]...");
@@ -244,7 +246,9 @@
final ParcelUuid requestUuid = request.getUuid();
if (requestUuid != null) {
- enforceCallerCanObserveDevicePresenceByUuid(mContext);
+ if (enforcePermissions) {
+ enforceCallerCanObserveDevicePresenceByUuid(mContext, packageName, userId);
+ }
if (!mObservableUuidStore.isUuidBeingObserved(requestUuid, userId, packageName)) {
Slog.i(TAG, "UUID=[" + requestUuid + "], package=[" + packageName + "], userId=["
@@ -283,7 +287,7 @@
* For legacy device presence below Android V.
*
* @deprecated Use {@link #startObservingDevicePresence(ObservingDevicePresenceRequest, String,
- * int)}
+ * int, boolean)}
*/
@Deprecated
public void startObservingDevicePresence(int userId, String packageName, String deviceAddress)
@@ -306,14 +310,14 @@
startObservingDevicePresence(
new ObservingDevicePresenceRequest.Builder().setAssociationId(association.getId())
- .build(), packageName, userId);
+ .build(), packageName, userId, /* enforcePermissions */ true);
}
/**
* For legacy device presence below Android V.
*
* @deprecated Use {@link #stopObservingDevicePresence(ObservingDevicePresenceRequest, String,
- * int)}
+ * int, boolean)}
*/
@Deprecated
public void stopObservingDevicePresence(int userId, String packageName, String deviceAddress)
@@ -336,7 +340,7 @@
stopObservingDevicePresence(
new ObservingDevicePresenceRequest.Builder().setAssociationId(association.getId())
- .build(), packageName, userId);
+ .build(), packageName, userId, /* enforcePermissions */ true);
}
/**
diff --git a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
index 796d285..c927cd0 100644
--- a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
+++ b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
@@ -35,6 +35,8 @@
import static android.os.Process.SYSTEM_UID;
import static android.os.UserHandle.getCallingUserId;
+import static com.android.server.companion.utils.RolesUtils.isRoleHolder;
+
import static java.util.Collections.unmodifiableMap;
import android.Manifest;
@@ -44,6 +46,7 @@
import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
import android.content.Context;
+import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
@@ -203,11 +206,9 @@
/**
* Require the caller to hold necessary permission to observe device presence by UUID.
*/
- public static void enforceCallerCanObserveDevicePresenceByUuid(@NonNull Context context) {
- if (context.checkCallingPermission(REQUEST_OBSERVE_DEVICE_UUID_PRESENCE)
- != PERMISSION_GRANTED
- || context.checkCallingPermission(BLUETOOTH_SCAN) != PERMISSION_GRANTED
- || context.checkCallingPermission(BLUETOOTH_CONNECT) != PERMISSION_GRANTED) {
+ public static void enforceCallerCanObserveDevicePresenceByUuid(@NonNull Context context,
+ String packageName, int userId) {
+ if (!hasRequirePermissions(context, packageName, userId)) {
throw new SecurityException("Caller (uid=" + getCallingUid() + ") does not have "
+ "permissions to request observing device presence base on the UUID");
}
@@ -234,6 +235,17 @@
return sAppOpsService;
}
+ private static boolean hasRequirePermissions(
+ @NonNull Context context, String packageName, int userId) {
+ return context.checkCallingPermission(
+ REQUEST_OBSERVE_DEVICE_UUID_PRESENCE) == PERMISSION_GRANTED
+ && context.checkCallingPermission(BLUETOOTH_SCAN) == PERMISSION_GRANTED
+ && context.checkCallingPermission(BLUETOOTH_CONNECT) == PERMISSION_GRANTED
+ && Boolean.TRUE.equals(Binder.withCleanCallingIdentity(
+ () -> isRoleHolder(context, userId, packageName,
+ DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)));
+ }
+
// DO NOT USE DIRECTLY! Access via getAppOpsService().
private static IAppOpsService sAppOpsService = null;
diff --git a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
index bc35fea..38bbfc4 100644
--- a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
+++ b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
@@ -47,6 +47,7 @@
import android.app.contextualsearch.ContextualSearchState;
import android.app.contextualsearch.IContextualSearchCallback;
import android.app.contextualsearch.IContextualSearchManager;
+import android.app.contextualsearch.flags.Flags;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -91,6 +92,8 @@
private static final String TAG = ContextualSearchManagerService.class.getSimpleName();
private static final int MSG_RESET_TEMPORARY_PACKAGE = 0;
private static final int MAX_TEMP_PACKAGE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+ private static final int MSG_INVALIDATE_TOKEN = 1;
+ private static final int MAX_TOKEN_VALID_DURATION_MS = 1_000 * 60 * 10; // 10 minutes
private final Context mContext;
private final ActivityTaskManagerInternal mAtmInternal;
@@ -145,6 +148,8 @@
private Handler mTemporaryHandler;
@GuardedBy("this")
private String mTemporaryPackage = null;
+ @GuardedBy("this")
+ private long mTokenValidDurationMs = MAX_TOKEN_VALID_DURATION_MS;
@GuardedBy("mLock")
private IContextualSearchCallback mStateCallback;
@@ -212,6 +217,29 @@
}
}
+ void resetTokenValidDurationMs() {
+ setTokenValidDurationMs(MAX_TOKEN_VALID_DURATION_MS);
+ }
+
+ void setTokenValidDurationMs(int durationMs) {
+ synchronized (this) {
+ enforceOverridingPermission("setTokenValidDurationMs");
+ if (durationMs > MAX_TOKEN_VALID_DURATION_MS) {
+ throw new IllegalArgumentException(
+ "Token max duration is " + MAX_TOKEN_VALID_DURATION_MS + " (called with "
+ + durationMs + ")");
+ }
+ mTokenValidDurationMs = durationMs;
+ if (DEBUG_USER) Log.d(TAG, "mTokenValidDurationMs set to " + durationMs);
+ }
+ }
+
+ private long getTokenValidDurationMs() {
+ synchronized (this) {
+ return mTokenValidDurationMs;
+ }
+ }
+
private Intent getResolvedLaunchIntent() {
synchronized (this) {
// If mTemporaryPackage is not null, use it to get the ContextualSearch intent.
@@ -356,15 +384,51 @@
}
private class ContextualSearchManagerStub extends IContextualSearchManager.Stub {
+ @GuardedBy("this")
+ private Handler mTokenHandler;
private @Nullable CallbackToken mToken;
+ private void invalidateToken() {
+ synchronized (this) {
+ if (mTokenHandler != null) {
+ mTokenHandler.removeMessages(MSG_INVALIDATE_TOKEN);
+ mTokenHandler = null;
+ }
+ if (DEBUG_USER) Log.d(TAG, "mToken invalidated.");
+ mToken = null;
+ }
+ }
+
+ private void issueToken() {
+ synchronized (this) {
+ mToken = new CallbackToken();
+ if (mTokenHandler == null) {
+ mTokenHandler = new Handler(Looper.getMainLooper(), null, true) {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_INVALIDATE_TOKEN) {
+ invalidateToken();
+ } else {
+ Slog.wtf(TAG, "invalid token handler msg: " + msg);
+ }
+ }
+ };
+ } else {
+ mTokenHandler.removeMessages(MSG_INVALIDATE_TOKEN);
+ }
+ mTokenHandler.sendEmptyMessageDelayed(
+ MSG_INVALIDATE_TOKEN, getTokenValidDurationMs());
+ }
+ }
+
@Override
public void startContextualSearch(int entrypoint) {
synchronized (this) {
if (DEBUG_USER) Log.d(TAG, "startContextualSearch");
enforcePermission("startContextualSearch");
mAssistDataRequester.cancel();
- mToken = new CallbackToken();
+ // Creates a new CallbackToken at mToken and an expiration handler.
+ issueToken();
// We get the launch intent with the system server's identity because the system
// server has READ_FRAME_BUFFER permission to get the screenshot and because only
// the system server can invoke non-exported activities.
@@ -397,7 +461,18 @@
}
return;
}
- mToken = null;
+ invalidateToken();
+ if (Flags.enableTokenRefresh()) {
+ issueToken();
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(ContextualSearchManager.EXTRA_TOKEN, mToken);
+ try {
+ callback.onResult(
+ new ContextualSearchState(null, null, bundle));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error invoking ContextualSearchCallback", e);
+ }
+ }
synchronized (mLock) {
mStateCallback = callback;
}
diff --git a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerShellCommand.java b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerShellCommand.java
index 5777e1d..66a4e7b 100644
--- a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerShellCommand.java
+++ b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerShellCommand.java
@@ -52,6 +52,19 @@
+ packageName + " for " + duration + "ms");
break;
}
+ case "token-duration": {
+ String durationStr = getNextArg();
+ if (durationStr == null) {
+ mService.resetTokenValidDurationMs();
+ pw.println("ContextualSearchManagerService token duration reset.");
+ return 0;
+ }
+ final int durationMs = Integer.parseInt(durationStr);
+ mService.setTokenValidDurationMs(durationMs);
+ pw.println("ContextualSearchManagerService temporarily set token duration"
+ + " to " + durationMs + "ms");
+ break;
+ }
}
}
break;
@@ -72,6 +85,9 @@
pw.println(" Temporarily (for DURATION ms) changes the Contextual Search "
+ "implementation.");
pw.println(" To reset, call without any arguments.");
+ pw.println(" set token-duration [DURATION]");
+ pw.println(" Changes the Contextual Search token duration to DURATION ms.");
+ pw.println(" To reset, call without any arguments.");
pw.println("");
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 2c04883..f5a297b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -174,6 +174,12 @@
*/
static final String KEY_ENABLE_BATCHING_OOM_ADJ = "enable_batching_oom_adj";
+ /**
+ * How long to wait before scheduling another follow-up oomAdjuster update for time based state.
+ */
+ static final String KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION =
+ "follow_up_oomadj_update_wait_duration";
+
private static final int DEFAULT_MAX_CACHED_PROCESSES = 1024;
private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true;
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
@@ -236,7 +242,7 @@
static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60 * 1000;
static final long DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS = 60 * 1000;
- static final boolean DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE = true;
+ static final boolean DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE = false;
static final int DEFAULT_MAX_SERVICE_CONNECTIONS_PER_PROCESS = 3000;
@@ -254,6 +260,11 @@
private static final boolean DEFAULT_ENABLE_BATCHING_OOM_ADJ = Flags.batchingOomAdj();
/**
+ * The default value to {@link #KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION}.
+ */
+ private static final long DEFAULT_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION = 1000L;
+
+ /**
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
*/
private static final int
@@ -1149,6 +1160,10 @@
/** @see #KEY_ENABLE_BATCHING_OOM_ADJ */
public boolean ENABLE_BATCHING_OOM_ADJ = DEFAULT_ENABLE_BATCHING_OOM_ADJ;
+ /** @see #KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION */
+ public long FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION =
+ DEFAULT_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION;
+
/**
* Indicates whether PSS profiling in AppProfiler is disabled or not.
*/
@@ -1359,6 +1374,9 @@
case KEY_PROC_STATE_DEBUG_UIDS:
updateProcStateDebugUids();
break;
+ case KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION:
+ updateFollowUpOomAdjUpdateWaitDuration();
+ break;
default:
updateFGSPermissionEnforcementFlagsIfNecessary(name);
break;
@@ -2246,6 +2264,13 @@
DEFAULT_ENABLE_NEW_OOM_ADJ);
}
+ private void updateFollowUpOomAdjUpdateWaitDuration() {
+ FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION,
+ DEFAULT_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION);
+ }
+
private void updateFGSPermissionEnforcementFlagsIfNecessary(@NonNull String name) {
ForegroundServiceTypePolicy.getDefaultPolicy()
.updatePermissionEnforcementFlagIfNecessary(name);
@@ -2514,6 +2539,9 @@
pw.print(" ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION=");
pw.println(mEnableWaitForFinishAttachApplication);
+ pw.print(" "); pw.print(KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION);
+ pw.print("="); pw.println(FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION);
+
synchronized (mProcStateDebugUids) {
pw.print(" "); pw.print(KEY_PROC_STATE_DEBUG_UIDS);
pw.print("="); pw.println(mProcStateDebugUids);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 44e522f..d750065 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1663,6 +1663,7 @@
static final int BIND_APPLICATION_TIMEOUT_HARD_MSG = 83;
static final int SERVICE_FGS_TIMEOUT_MSG = 84;
static final int SERVICE_FGS_CRASH_TIMEOUT_MSG = 85;
+ static final int FOLLOW_UP_OOMADJUSTER_UPDATE_MSG = 86;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -2036,6 +2037,9 @@
case SERVICE_FGS_CRASH_TIMEOUT_MSG: {
mServices.onFgsCrashTimeout((ServiceRecord) msg.obj);
} break;
+ case FOLLOW_UP_OOMADJUSTER_UPDATE_MSG: {
+ handleFollowUpOomAdjusterUpdate();
+ } break;
}
}
}
@@ -5103,6 +5107,15 @@
mAnrHelper.appNotResponding(app, TimeoutRecord.forAppStart(anrMessage));
}
+ private void handleFollowUpOomAdjusterUpdate() {
+ // Remove any existing duplicate messages on the handler here while no lock is being held.
+ // If another follow up update is needed, it will be scheduled by OomAdjuster.
+ mHandler.removeMessages(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG);
+ synchronized (this) {
+ mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ }
+ }
+
/**
* @return The last part of the string of an intent's action.
*/
@@ -10224,6 +10237,19 @@
addStartInfoTimestampInternal(key, timestampNs, userId, callingUid);
}
+ @Override
+ public void reportStartInfoViewTimestamps(long renderThreadDrawStartTimeNs,
+ long framePresentedTimeNs) {
+ int callingUid = Binder.getCallingUid();
+ int userId = UserHandle.getUserId(callingUid);
+ addStartInfoTimestampInternal(
+ ApplicationStartInfo.START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME,
+ renderThreadDrawStartTimeNs, userId, callingUid);
+ addStartInfoTimestampInternal(
+ ApplicationStartInfo.START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE,
+ framePresentedTimeNs, userId, callingUid);
+ }
+
private void addStartInfoTimestampInternal(int key, long timestampNs, int userId, int uid) {
mProcessList.getAppStartInfoTracker().addTimestampToStart(
Settings.getPackageNameForUid(mContext, uid),
diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index 3042b2a..4a7ad31 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -1195,21 +1195,8 @@
// Records are sorted newest to oldest, grab record at index 0.
ApplicationStartInfo startInfo = mInfos.get(0);
- int startupState = startInfo.getStartupState();
- // If startup state is error then don't accept any further timestamps.
- if (startupState == ApplicationStartInfo.STARTUP_STATE_ERROR) {
- if (DEBUG) Slog.d(TAG, "Startup state is error, not accepting new timestamps.");
- return;
- }
-
- // If startup state is first frame drawn then only accept fully drawn timestamp.
- if (startupState == ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN
- && key != ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN) {
- if (DEBUG) {
- Slog.d(TAG, "Startup state is first frame drawn and timestamp is not fully "
- + "drawn, not accepting new timestamps.");
- }
+ if (!isAddTimestampAllowed(startInfo, key, timestampNs)) {
return;
}
@@ -1222,6 +1209,55 @@
}
}
+ private boolean isAddTimestampAllowed(ApplicationStartInfo startInfo, int key,
+ long timestampNs) {
+ int startupState = startInfo.getStartupState();
+
+ // If startup state is error then don't accept any further timestamps.
+ if (startupState == ApplicationStartInfo.STARTUP_STATE_ERROR) {
+ if (DEBUG) Slog.d(TAG, "Startup state is error, not accepting new timestamps.");
+ return false;
+ }
+
+ Map<Integer, Long> timestamps = startInfo.getStartupTimestamps();
+
+ if (startupState == ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN) {
+ switch (key) {
+ case ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN:
+ // Allowed, continue to confirm it's not already added.
+ break;
+ case ApplicationStartInfo.START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME:
+ Long firstFrameTimeNs = timestamps
+ .get(ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME);
+ if (firstFrameTimeNs == null) {
+ // This should never happen. State can't be first frame drawn if first
+ // frame timestamp was not provided.
+ return false;
+ }
+
+ if (timestampNs > firstFrameTimeNs) {
+ // Initial renderthread frame has to occur before first frame.
+ return false;
+ }
+
+ // Allowed, continue to confirm it's not already added.
+ break;
+ case ApplicationStartInfo.START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE:
+ // Allowed, continue to confirm it's not already added.
+ break;
+ default:
+ return false;
+ }
+ }
+
+ if (timestamps.get(key) != null) {
+ // Timestamp should not occur more than once for a given start.
+ return false;
+ }
+
+ return true;
+ }
+
@GuardedBy("mLock")
void dumpLocked(PrintWriter pw, String prefix, SimpleDateFormat sdf) {
if (mMonitoringModeEnabled) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index fc81d3e..e8af82e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -49,6 +49,7 @@
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_COMPONENT_DISABLED;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_EXECUTING_SERVICE;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FINISH_RECEIVER;
+import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FOLLOW_UP;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_GET_PROVIDER;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_NONE;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_BEGIN;
@@ -91,6 +92,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
import static com.android.server.am.ActivityManagerService.DISPATCH_OOM_ADJ_OBSERVER_MSG;
+import static com.android.server.am.ActivityManagerService.FOLLOW_UP_OOMADJUSTER_UPDATE_MSG;
import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
import static com.android.server.am.ActivityManagerService.TAG_BACKUP;
import static com.android.server.am.ActivityManagerService.TAG_LRU;
@@ -226,6 +228,8 @@
return AppProtoEnums.OOM_ADJ_REASON_RESTRICTION_CHANGE;
case OOM_ADJ_REASON_COMPONENT_DISABLED:
return AppProtoEnums.OOM_ADJ_REASON_COMPONENT_DISABLED;
+ case OOM_ADJ_REASON_FOLLOW_UP:
+ return AppProtoEnums.OOM_ADJ_REASON_FOLLOW_UP;
default:
return AppProtoEnums.OOM_ADJ_REASON_UNKNOWN_TO_PROTO;
}
@@ -280,6 +284,8 @@
return OOM_ADJ_REASON_METHOD + "_restrictionChange";
case OOM_ADJ_REASON_COMPONENT_DISABLED:
return OOM_ADJ_REASON_METHOD + "_componentDisabled";
+ case OOM_ADJ_REASON_FOLLOW_UP:
+ return OOM_ADJ_REASON_METHOD + "_followUp";
default:
return "_unknown";
}
@@ -370,6 +376,7 @@
protected final int[] mTmpSchedGroup = new int[1];
final ActivityManagerService mService;
+ final Injector mInjector;
final ProcessList mProcessList;
final ActivityManagerGlobalLock mProcLock;
@@ -420,12 +427,33 @@
@GuardedBy("mService")
protected int mProcessStateCurTop = PROCESS_STATE_TOP;
- /** Overrideable by a test */
+ @GuardedBy("mService")
+ private final ArraySet<ProcessRecord> mFollowUpUpdateSet = new ArraySet<>();
+
+ private static final long NO_FOLLOW_UP_TIME = Long.MAX_VALUE;
+ @GuardedBy("mService")
+ private long mNextFollowUpUpdateUptimeMs = NO_FOLLOW_UP_TIME;
+
@VisibleForTesting
- protected boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId,
+ public static class Injector {
+ boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId,
+ ApplicationInfo app, boolean defaultValue) {
+ return PlatformCompatCache.getInstance()
+ .isChangeEnabled(cachedCompatChangeId, app, defaultValue);
+ }
+
+ long getUptimeMillis() {
+ return SystemClock.uptimeMillis();
+ }
+
+ long getElapsedRealtimeMillis() {
+ return SystemClock.elapsedRealtime();
+ }
+ }
+
+ boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId,
ApplicationInfo app, boolean defaultValue) {
- return PlatformCompatCache.getInstance()
- .isChangeEnabled(cachedCompatChangeId, app, defaultValue);
+ return mInjector.isChangeEnabled(cachedCompatChangeId, app, defaultValue);
}
OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
@@ -443,7 +471,18 @@
OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
ServiceThread adjusterThread) {
+ this(service, processList, activeUids, adjusterThread, new Injector());
+ }
+
+ OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
+ Injector injector) {
+ this(service, processList, activeUids, createAdjusterThread(), injector);
+ }
+
+ OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
+ ServiceThread adjusterThread, Injector injector) {
mService = service;
+ mInjector = injector;
mProcessList = processList;
mProcLock = service.mProcLock;
mActiveUids = activeUids;
@@ -631,8 +670,8 @@
// processes, its adj could be still unknown as of now, assign one.
processes.add(app);
assignCachedAdjIfNecessary(processes);
- applyOomAdjLSP(app, false, SystemClock.uptimeMillis(),
- SystemClock.elapsedRealtime(), oomAdjReason);
+ applyOomAdjLSP(app, false, mInjector.getUptimeMillis(),
+ mInjector.getElapsedRealtimeMillis(), oomAdjReason);
}
mTmpProcessList.clear();
mService.clearPendingTopAppLocked();
@@ -849,6 +888,40 @@
}
@GuardedBy("mService")
+ void updateOomAdjFollowUpTargetsLocked() {
+ final long now = mInjector.getUptimeMillis();
+ long nextFollowUpUptimeMs = Long.MAX_VALUE;
+ mNextFollowUpUpdateUptimeMs = NO_FOLLOW_UP_TIME;
+ for (int i = mFollowUpUpdateSet.size() - 1; i >= 0; i--) {
+ final ProcessRecord proc = mFollowUpUpdateSet.valueAtUnchecked(i);
+ final long followUpUptimeMs = proc.mState.getFollowupUpdateUptimeMs();
+
+ if (proc.isKilled()) {
+ // Process is dead, just remove from follow up set.
+ mFollowUpUpdateSet.removeAt(i);
+ } else if (followUpUptimeMs <= now) {
+ // Add processes that need a follow up update.
+ mPendingProcessSet.add(proc);
+ proc.mState.setFollowupUpdateUptimeMs(NO_FOLLOW_UP_TIME);
+ mFollowUpUpdateSet.removeAt(i);
+ } else if (followUpUptimeMs < nextFollowUpUptimeMs) {
+ // Figure out when to schedule the next follow up update.
+ nextFollowUpUptimeMs = followUpUptimeMs;
+ } else if (followUpUptimeMs == NO_FOLLOW_UP_TIME) {
+ // The follow up is no longer needed for this process.
+ mFollowUpUpdateSet.removeAt(i);
+ }
+ }
+
+ if (nextFollowUpUptimeMs != Long.MAX_VALUE) {
+ // There is still at least one process that needs a follow up.
+ scheduleFollowUpOomAdjusterUpdateLocked(nextFollowUpUptimeMs, now);
+ }
+
+ updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_FOLLOW_UP);
+ }
+
+ @GuardedBy("mService")
protected void performUpdateOomAdjPendingTargetsLocked(@OomAdjReason int oomAdjReason) {
final ProcessRecord topApp = mService.getTopApp();
@@ -899,8 +972,8 @@
if (startProfiling) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
}
- final long now = SystemClock.uptimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long now = mInjector.getUptimeMillis();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
final int numProc = activeProcesses.size();
@@ -1026,7 +1099,7 @@
updateUidsLSP(activeUids, nowElapsed);
synchronized (mService.mProcessStats.mLock) {
- final long nowUptime = SystemClock.uptimeMillis();
+ final long nowUptime = mInjector.getUptimeMillis();
if (mService.mProcessStats.shouldWriteNowLocked(nowUptime)) {
mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService,
mService.mProcessStats));
@@ -1037,7 +1110,7 @@
}
if (DEBUG_OOM_ADJ) {
- final long duration = SystemClock.uptimeMillis() - now;
+ final long duration = mInjector.getUptimeMillis() - now;
if (false) {
Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms",
new RuntimeException("here").fillInStackTrace());
@@ -1051,7 +1124,7 @@
protected void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
final int numLru = lruList.size();
if (mConstants.USE_TIERED_CACHED_ADJ) {
- final long now = SystemClock.uptimeMillis();
+ final long now = mInjector.getUptimeMillis();
for (int i = numLru - 1; i >= 0; i--) {
ProcessRecord app = lruList.get(i);
final ProcessStateRecord state = app.mState;
@@ -1734,6 +1807,10 @@
int prevProcState = getInitialProcState(app);
int prevCapability = getInitialCapability(app);
+ // Remove any follow up update this process might have. It will be rescheduled if still
+ // needed.
+ app.mState.setFollowupUpdateUptimeMs(NO_FOLLOW_UP_TIME);
+
if (app.getThread() == null) {
state.setAdjSeq(mAdjSeq);
state.setCurrentSchedulingGroup(SCHED_GROUP_BACKGROUND);
@@ -2001,6 +2078,8 @@
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app);
}
+ maybeSetProcessFollowUpUpdateLocked(app,
+ state.getLastTopTime() + mConstants.TOP_TO_FGS_GRACE_DURATION, now);
}
// If the app was recently in the foreground and has expedited jobs running,
@@ -2021,6 +2100,9 @@
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg for EJ: " + app);
}
+ maybeSetProcessFollowUpUpdateLocked(app,
+ state.getLastTopTime() + mConstants.TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION,
+ now);
}
if (adj > PERCEPTIBLE_APP_ADJ
@@ -2086,7 +2168,7 @@
// app to be demoted to cached.
if (procState >= PROCESS_STATE_LAST_ACTIVITY
&& state.getSetProcState() == PROCESS_STATE_LAST_ACTIVITY
- && (state.getLastStateTime() + mConstants.MAX_PREVIOUS_TIME) < now) {
+ && (state.getLastStateTime() + mConstants.MAX_PREVIOUS_TIME) <= now) {
procState = PROCESS_STATE_LAST_ACTIVITY;
schedGroup = SCHED_GROUP_BACKGROUND;
state.setAdjType("previous-expired");
@@ -2110,6 +2192,14 @@
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app);
}
}
+ final long lastStateTime;
+ if (state.getSetProcState() == PROCESS_STATE_LAST_ACTIVITY) {
+ lastStateTime = state.getLastStateTime();
+ } else {
+ lastStateTime = now;
+ }
+ maybeSetProcessFollowUpUpdateLocked(app,
+ lastStateTime + mConstants.MAX_PREVIOUS_TIME, now);
}
}
@@ -2198,6 +2288,8 @@
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise adj to started service: " + app);
}
+ maybeSetProcessFollowUpUpdateLocked(app,
+ s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY, now);
}
}
// If we have let the service slide into the background
@@ -2352,6 +2444,8 @@
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise adj to recent provider: " + app);
}
+ maybeSetProcessFollowUpUpdateLocked(app,
+ ppr.getLastProviderTime() + mConstants.CONTENT_PROVIDER_RETAIN_TIME, now);
}
if (procState > PROCESS_STATE_LAST_ACTIVITY) {
procState = PROCESS_STATE_LAST_ACTIVITY;
@@ -2360,6 +2454,8 @@
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise procstate to recent provider: " + app);
}
+ maybeSetProcessFollowUpUpdateLocked(app,
+ ppr.getLastProviderTime() + mConstants.CONTENT_PROVIDER_RETAIN_TIME, now);
}
}
@@ -3672,7 +3768,7 @@
if (N <= 0) {
return;
}
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
final long maxBgTime = nowElapsed - mConstants.BACKGROUND_SETTLE_TIME;
long nextTime = 0;
if (mService.mLocalPowerManager != null) {
@@ -3907,7 +4003,7 @@
}
// Take a dry run of the computeServiceHostOomAdjLSP, this would't be expensive
// since it's only evaluating one service connection.
- return computeServiceHostOomAdjLSP(cr, app, client, SystemClock.uptimeMillis(),
+ return computeServiceHostOomAdjLSP(cr, app, client, mInjector.getUptimeMillis(),
mService.getTopApp(), false, false, false, OOM_ADJ_REASON_NONE,
CACHED_APP_MIN_ADJ, false, true /* dryRun */);
}
@@ -3942,7 +4038,7 @@
// The provider host process has better states than the client, so no change.
return false;
}
- return computeProviderHostOomAdjLSP(null, app, client, SystemClock.uptimeMillis(),
+ return computeProviderHostOomAdjLSP(null, app, client, mInjector.getUptimeMillis(),
mService.getTopApp(), false, false, false, OOM_ADJ_REASON_NONE, CACHED_APP_MIN_ADJ,
false, true /* dryRun */);
}
@@ -3970,4 +4066,43 @@
}
return false;
}
+
+ @GuardedBy("mService")
+ private void maybeSetProcessFollowUpUpdateLocked(ProcessRecord proc,
+ long updateUptimeMs, long now) {
+ if (!Flags.followUpOomadjUpdates()) {
+ return;
+ }
+ if (updateUptimeMs <= now) {
+ // Time sensitive period has already passed. No need to schedule a follow up.
+ return;
+ }
+
+ mFollowUpUpdateSet.add(proc);
+ proc.mState.setFollowupUpdateUptimeMs(updateUptimeMs);
+
+ scheduleFollowUpOomAdjusterUpdateLocked(updateUptimeMs, now);
+ }
+
+
+ @GuardedBy("mService")
+ private void scheduleFollowUpOomAdjusterUpdateLocked(long updateUptimeMs,
+ long now) {
+ if (updateUptimeMs + mConstants.FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION
+ >= mNextFollowUpUpdateUptimeMs) {
+ // Update time is too close or later than the next follow up update.
+ return;
+ }
+ if (updateUptimeMs < now + mConstants.FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION) {
+ // Use a minimum delay for the follow up to possibly batch multiple process
+ // evaluations and avoid rapid updates.
+ updateUptimeMs = now + mConstants.FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION;
+ }
+
+ // Schedulate a follow up update. Don't bother deleting existing handler messages, they
+ // will be cleared during the message while no locks are being held.
+ mNextFollowUpUpdateUptimeMs = updateUptimeMs;
+ mService.mHandler.sendEmptyMessageAtTime(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG,
+ mNextFollowUpUpdateUptimeMs);
+ }
}
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
index a67af89..21842db 100644
--- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -68,7 +68,6 @@
import android.app.ActivityManagerInternal.OomAdjReason;
import android.content.pm.ServiceInfo;
import android.os.IBinder;
-import android.os.SystemClock;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -764,6 +763,11 @@
super(service, processList, activeUids, adjusterThread);
}
+ OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
+ ActiveUids activeUids, Injector injector) {
+ super(service, processList, activeUids, injector);
+ }
+
private final ProcessRecordNodes mProcessRecordProcStateNodes = new ProcessRecordNodes(
ProcessRecordNode.NODE_TYPE_PROC_STATE, PROC_STATE_SLOTS.length);
private final ProcessRecordNodes mProcessRecordAdjNodes = new ProcessRecordNodes(
@@ -924,8 +928,8 @@
@GuardedBy({"mService", "mProcLock"})
private void fullUpdateLSP(@OomAdjReason int oomAdjReason) {
final ProcessRecord topApp = mService.getTopApp();
- final long now = SystemClock.uptimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long now = mInjector.getUptimeMillis();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
mAdjSeq++;
@@ -1015,8 +1019,8 @@
@GuardedBy({"mService", "mProcLock"})
private void partialUpdateLSP(@OomAdjReason int oomAdjReason, ArraySet<ProcessRecord> targets) {
final ProcessRecord topApp = mService.getTopApp();
- final long now = SystemClock.uptimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long now = mInjector.getUptimeMillis();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
ActiveUids activeUids = mTmpUidRecords;
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 8de748e..7c64298 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -449,6 +449,9 @@
@GuardedBy("mService")
private boolean mScheduleLikeTopApp = false;
+ @GuardedBy("mService")
+ private long mFollowupUpdateUptimeMs = Long.MAX_VALUE;
+
ProcessStateRecord(ProcessRecord app) {
mApp = app;
mService = app.mService;
@@ -1164,6 +1167,16 @@
mScheduleLikeTopApp = scheduleLikeTopApp;
}
+ @GuardedBy("mService")
+ long getFollowupUpdateUptimeMs() {
+ return mFollowupUpdateUptimeMs;
+ }
+
+ @GuardedBy("mService")
+ void setFollowupUpdateUptimeMs(long updateUptimeMs) {
+ mFollowupUpdateUptimeMs = updateUptimeMs;
+ }
+
@GuardedBy(anyOf = {"mService", "mProcLock"})
public String makeAdjReason() {
if (mAdjSource != null || mAdjTarget != null) {
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 3df5687..cbea7aa 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -142,6 +142,7 @@
"arc_next",
"art_mainline",
"art_performance",
+ "attack_tools",
"avic",
"biometrics",
"biometrics_framework",
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 2abfad9..bb52857 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -142,3 +142,13 @@
bug: "244232958"
is_fixed_read_only: true
}
+
+flag {
+ name: "follow_up_oomadj_updates"
+ namespace: "backstage_power"
+ description: "Schedule follow up OomAdjuster updates for time sensitive states."
+ bug: "333450932"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 390ee96..17835b2 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -18,6 +18,10 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.os.Build.VERSION_CODES.M;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__OK;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__ERROR_ILLEGAL_ARGUMENT;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__ERROR_INVALID_OPERATION;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -40,6 +44,7 @@
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.hardware.CameraExtensionSessionStats;
+import android.hardware.CameraFeatureCombinationStats;
import android.hardware.CameraSessionStats;
import android.hardware.CameraStreamStats;
import android.hardware.ICameraService;
@@ -217,7 +222,7 @@
// Map of currently active camera IDs
private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>();
- private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>();
+ private final List<CameraEvent> mCameraEventHistory = new ArrayList<CameraEvent>();
private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc";
private static final IBinder nfcInterfaceToken = new Binder();
@@ -228,9 +233,16 @@
/*corePoolSize*/ 1);
/**
+ * Interface to track camera analytics
+ */
+ private interface CameraEvent {
+ void logSelf();
+ }
+
+ /**
* Structure to track camera usage
*/
- private static class CameraUsageEvent {
+ private static class CameraUsageEvent implements CameraEvent {
public final String mCameraId;
public final int mCameraFacing;
public final String mClientName;
@@ -311,6 +323,214 @@
public long getDuration() {
return mCompleted ? mDurationOrStartTimeMs : 0;
}
+
+ public void logSelf() {
+ int facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__UNKNOWN;
+ switch(mCameraFacing) {
+ case CameraSessionStats.CAMERA_FACING_BACK:
+ facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__BACK;
+ break;
+ case CameraSessionStats.CAMERA_FACING_FRONT:
+ facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__FRONT;
+ break;
+ case CameraSessionStats.CAMERA_FACING_EXTERNAL:
+ facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__EXTERNAL;
+ break;
+ default:
+ Slog.w(TAG, "Unknown camera facing: " + mCameraFacing);
+ }
+
+ int extensionType = FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_NONE;
+ boolean extensionIsAdvanced = false;
+ int extensionCaptureFormat = ImageFormat.UNKNOWN;
+ if (mExtSessionStats != null) {
+ switch (mExtSessionStats.type) {
+ case CameraExtensionSessionStats.Type.EXTENSION_AUTOMATIC:
+ extensionType = FrameworkStatsLog
+ .CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_AUTOMATIC;
+ break;
+ case CameraExtensionSessionStats.Type.EXTENSION_FACE_RETOUCH:
+ extensionType = FrameworkStatsLog
+ .CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_FACE_RETOUCH;
+ break;
+ case CameraExtensionSessionStats.Type.EXTENSION_BOKEH:
+ extensionType =
+ FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_BOKEH;
+ break;
+ case CameraExtensionSessionStats.Type.EXTENSION_HDR:
+ extensionType =
+ FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_HDR;
+ break;
+ case CameraExtensionSessionStats.Type.EXTENSION_NIGHT:
+ extensionType =
+ FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_NIGHT;
+ break;
+ default:
+ Slog.w(TAG, "Unknown extension type: " + mExtSessionStats.type);
+ }
+ extensionIsAdvanced = mExtSessionStats.isAdvanced;
+ if (Flags.analytics24q3()) {
+ extensionCaptureFormat = mExtSessionStats.captureFormat;
+ }
+ }
+
+ int streamCount = 0;
+ if (mStreamStats != null) {
+ streamCount = mStreamStats.size();
+ }
+ if (CameraServiceProxy.DEBUG) {
+ String ultrawideDebug = Flags.logUltrawideUsage()
+ ? ", wideAngleUsage " + mUsedUltraWide
+ : "";
+ String zoomOverrideDebug = Flags.logZoomOverrideUsage()
+ ? ", zoomOverrideUsage " + mUsedZoomOverride
+ : "";
+ String mostRequestedFpsRangeDebug = Flags.analytics24q3()
+ ? ", mostRequestedFpsRange " + mMostRequestedFpsRange
+ : "";
+ String extensionCaptureFormatDebug = Flags.analytics24q3()
+ ? " extensionCaptureFormat " + mExtSessionStats.captureFormat
+ : "";
+
+ Slog.v(TAG, "CAMERA_ACTION_EVENT: action " + mAction
+ + " clientName " + mClientName
+ + ", duration " + getDuration()
+ + ", APILevel " + mAPILevel
+ + ", cameraId " + mCameraId
+ + ", facing " + facing
+ + ", isNdk " + mIsNdk
+ + ", latencyMs " + mLatencyMs
+ + ", operatingMode " + mOperatingMode
+ + ", internalReconfigure " + mInternalReconfigure
+ + ", requestCount " + mRequestCount
+ + ", resultErrorCount " + mResultErrorCount
+ + ", deviceError " + mDeviceError
+ + ", streamCount is " + streamCount
+ + ", userTag is " + mUserTag
+ + ", videoStabilizationMode " + mVideoStabilizationMode
+ + ultrawideDebug
+ + zoomOverrideDebug
+ + mostRequestedFpsRangeDebug
+ + ", logId " + mLogId
+ + ", sessionIndex " + mSessionIndex
+ + ", mExtSessionStats {type " + extensionType
+ + " isAdvanced " + extensionIsAdvanced
+ + extensionCaptureFormatDebug + "}");
+ }
+
+ // Convert from CameraStreamStats to CameraStreamProto
+ CameraStreamProto[] streamProtos = new CameraStreamProto[MAX_STREAM_STATISTICS];
+ for (int i = 0; i < MAX_STREAM_STATISTICS; i++) {
+ streamProtos[i] = new CameraStreamProto();
+ if (i < streamCount) {
+ CameraStreamStats streamStats = mStreamStats.get(i);
+ streamProtos[i].width = streamStats.getWidth();
+ streamProtos[i].height = streamStats.getHeight();
+ streamProtos[i].format = streamStats.getFormat();
+ streamProtos[i].dataSpace = streamStats.getDataSpace();
+ streamProtos[i].usage = streamStats.getUsage();
+ streamProtos[i].requestCount = streamStats.getRequestCount();
+ streamProtos[i].errorCount = streamStats.getErrorCount();
+ streamProtos[i].firstCaptureLatencyMillis = streamStats.getStartLatencyMs();
+ streamProtos[i].maxHalBuffers = streamStats.getMaxHalBuffers();
+ streamProtos[i].maxAppBuffers = streamStats.getMaxAppBuffers();
+ streamProtos[i].histogramType = streamStats.getHistogramType();
+ streamProtos[i].histogramBins = streamStats.getHistogramBins();
+ streamProtos[i].histogramCounts = streamStats.getHistogramCounts();
+ streamProtos[i].dynamicRangeProfile = streamStats.getDynamicRangeProfile();
+ streamProtos[i].streamUseCase = streamStats.getStreamUseCase();
+ streamProtos[i].colorSpace = streamStats.getColorSpace();
+
+ if (CameraServiceProxy.DEBUG) {
+ String histogramTypeName =
+ cameraHistogramTypeToString(streamProtos[i].histogramType);
+ Slog.v(TAG, "Stream " + i + ": width " + streamProtos[i].width
+ + ", height " + streamProtos[i].height
+ + ", format " + streamProtos[i].format
+ + ", maxPreviewFps " + streamStats.getMaxPreviewFps()
+ + ", dataSpace " + streamProtos[i].dataSpace
+ + ", usage " + streamProtos[i].usage
+ + ", requestCount " + streamProtos[i].requestCount
+ + ", errorCount " + streamProtos[i].errorCount
+ + ", firstCaptureLatencyMillis "
+ + streamProtos[i].firstCaptureLatencyMillis
+ + ", maxHalBuffers " + streamProtos[i].maxHalBuffers
+ + ", maxAppBuffers " + streamProtos[i].maxAppBuffers
+ + ", histogramType " + histogramTypeName
+ + ", histogramBins "
+ + Arrays.toString(streamProtos[i].histogramBins)
+ + ", histogramCounts "
+ + Arrays.toString(streamProtos[i].histogramCounts)
+ + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile
+ + ", streamUseCase " + streamProtos[i].streamUseCase
+ + ", colorSpace " + streamProtos[i].colorSpace);
+ }
+ }
+ }
+ FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_ACTION_EVENT, getDuration(),
+ mAPILevel, mClientName, facing, mCameraId, mAction, mIsNdk,
+ mLatencyMs, mOperatingMode, mInternalReconfigure,
+ mRequestCount, mResultErrorCount, mDeviceError,
+ streamCount, MessageNano.toByteArray(streamProtos[0]),
+ MessageNano.toByteArray(streamProtos[1]),
+ MessageNano.toByteArray(streamProtos[2]),
+ MessageNano.toByteArray(streamProtos[3]),
+ MessageNano.toByteArray(streamProtos[4]),
+ mUserTag, mVideoStabilizationMode,
+ mLogId, mSessionIndex,
+ extensionType, extensionIsAdvanced, mUsedUltraWide,
+ mUsedZoomOverride,
+ mMostRequestedFpsRange.getLower(), mMostRequestedFpsRange.getUpper(),
+ extensionCaptureFormat);
+
+ }
+ }
+ /**
+ * Structure to track feature combination query
+ */
+ private static class CameraFeatureCombinationQueryEvent implements CameraEvent {
+ private CameraFeatureCombinationStats mFeatureCombinationStats;
+
+ CameraFeatureCombinationQueryEvent(CameraFeatureCombinationStats featureCombinationStats) {
+ mFeatureCombinationStats = featureCombinationStats;
+ }
+
+ public void logSelf() {
+ int statusCode = -1;
+ switch (mFeatureCombinationStats.mStatus) {
+ case 0:
+ statusCode = CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__OK;
+ break;
+ case ICameraService.ERROR_ILLEGAL_ARGUMENT:
+ statusCode = CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__ERROR_ILLEGAL_ARGUMENT;
+ break;
+ case ICameraService.ERROR_INVALID_OPERATION:
+ statusCode = CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__ERROR_INVALID_OPERATION;
+ break;
+ default:
+ break;
+ }
+ if (statusCode == -1) {
+ Slog.w(TAG, "Unknown feature combination query status code: "
+ + mFeatureCombinationStats.mStatus);
+ return;
+ }
+
+ if (CameraServiceProxy.DEBUG) {
+ Slog.v(TAG, "CAMERA_FEATURE_COMBINATION_QUERY_EVENT: uid "
+ + mFeatureCombinationStats.mUid
+ + ", cameraId " + mFeatureCombinationStats.mCameraId
+ + ", queryType " + mFeatureCombinationStats.mQueryType
+ + ", featureCombination " + mFeatureCombinationStats.mFeatureCombination
+ + ", status " + statusCode);
+ }
+ FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_FEATURE_COMBINATION_QUERY_EVENT,
+ mFeatureCombinationStats.mUid,
+ mFeatureCombinationStats.mCameraId,
+ mFeatureCombinationStats.mQueryType,
+ mFeatureCombinationStats.mFeatureCombination,
+ statusCode);
+ }
}
private final class DisplayWindowListener extends IDisplayWindowListener.Stub {
@@ -625,6 +845,32 @@
}
@Override
+ public void notifyFeatureCombinationStats(CameraFeatureCombinationStats featureCombStats) {
+ if (!Flags.analytics24q3()) {
+ return;
+ }
+ if (Binder.getCallingUid() != Process.CAMERASERVER_UID) {
+ Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected "
+ + " camera service UID!");
+ return;
+ }
+
+ if (DEBUG) {
+ String combinationTypeStr = cameraFeatureCombinationTypeToString(
+ featureCombStats.mQueryType);
+ String combinationStr = cameraFeatureCombinationToString(
+ featureCombStats.mFeatureCombination);
+ Slog.v(TAG, "Camera " + featureCombStats.mCameraId
+ + " query " + combinationTypeStr
+ + " combination " + combinationStr
+ + " for client UID " + featureCombStats.mUid
+ + " returns " + featureCombStats.mStatus);
+ }
+
+ updateFeatureCombinationQuery(featureCombStats);
+ }
+
+ @Override
public boolean isCameraDisabled(int userId) {
if (Binder.getCallingUid() != Process.CAMERASERVER_UID) {
Slog.e(TAG, "Calling UID: " + Binder.getCallingUid()
@@ -684,7 +930,7 @@
switch (cmd.replace('-', '_')) {
case "dump_events":
int eventCount = mCameraServiceProxy.getUsageEventCount();
- mCameraServiceProxy.dumpUsageEvents();
+ mCameraServiceProxy.dumpCameraEvents();
pw.println("Camera usage events dumped: " + eventCount);
break;
default:
@@ -865,18 +1111,18 @@
}
private class EventWriterTask implements Runnable {
- private ArrayList<CameraUsageEvent> mEventList;
+ private List<CameraEvent> mEventList;
private static final long WRITER_SLEEP_MS = 100;
- public EventWriterTask(ArrayList<CameraUsageEvent> eventList) {
+ EventWriterTask(List<CameraEvent> eventList) {
mEventList = eventList;
}
@Override
public void run() {
if (mEventList != null) {
- for (CameraUsageEvent event : mEventList) {
- logCameraUsageEvent(event);
+ for (CameraEvent event : mEventList) {
+ event.logSelf();
try {
Thread.sleep(WRITER_SLEEP_MS);
} catch (InterruptedException e) {}
@@ -884,170 +1130,6 @@
mEventList.clear();
}
}
-
- /**
- * Write camera usage events to stats log.
- * Package-private
- */
- private void logCameraUsageEvent(CameraUsageEvent e) {
- int facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__UNKNOWN;
- switch(e.mCameraFacing) {
- case CameraSessionStats.CAMERA_FACING_BACK:
- facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__BACK;
- break;
- case CameraSessionStats.CAMERA_FACING_FRONT:
- facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__FRONT;
- break;
- case CameraSessionStats.CAMERA_FACING_EXTERNAL:
- facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__EXTERNAL;
- break;
- default:
- Slog.w(TAG, "Unknown camera facing: " + e.mCameraFacing);
- }
-
- int extensionType = FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_NONE;
- boolean extensionIsAdvanced = false;
- int extensionCaptureFormat = ImageFormat.UNKNOWN;
- if (e.mExtSessionStats != null) {
- switch (e.mExtSessionStats.type) {
- case CameraExtensionSessionStats.Type.EXTENSION_AUTOMATIC:
- extensionType = FrameworkStatsLog
- .CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_AUTOMATIC;
- break;
- case CameraExtensionSessionStats.Type.EXTENSION_FACE_RETOUCH:
- extensionType = FrameworkStatsLog
- .CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_FACE_RETOUCH;
- break;
- case CameraExtensionSessionStats.Type.EXTENSION_BOKEH:
- extensionType =
- FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_BOKEH;
- break;
- case CameraExtensionSessionStats.Type.EXTENSION_HDR:
- extensionType =
- FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_HDR;
- break;
- case CameraExtensionSessionStats.Type.EXTENSION_NIGHT:
- extensionType =
- FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_NIGHT;
- break;
- default:
- Slog.w(TAG, "Unknown extension type: " + e.mExtSessionStats.type);
- }
- extensionIsAdvanced = e.mExtSessionStats.isAdvanced;
- if (Flags.analytics24q3()) {
- extensionCaptureFormat = e.mExtSessionStats.captureFormat;
- }
- }
-
- int streamCount = 0;
- if (e.mStreamStats != null) {
- streamCount = e.mStreamStats.size();
- }
- if (CameraServiceProxy.DEBUG) {
- String ultrawideDebug = Flags.logUltrawideUsage()
- ? ", wideAngleUsage " + e.mUsedUltraWide
- : "";
- String zoomOverrideDebug = Flags.logZoomOverrideUsage()
- ? ", zoomOverrideUsage " + e.mUsedZoomOverride
- : "";
- String mostRequestedFpsRangeDebug = Flags.analytics24q3()
- ? ", mostRequestedFpsRange " + e.mMostRequestedFpsRange
- : "";
- String extensionCaptureFormatDebug = Flags.analytics24q3()
- ? " extensionCaptureFormat " + e.mExtSessionStats.captureFormat
- : "";
-
- Slog.v(TAG, "CAMERA_ACTION_EVENT: action " + e.mAction
- + " clientName " + e.mClientName
- + ", duration " + e.getDuration()
- + ", APILevel " + e.mAPILevel
- + ", cameraId " + e.mCameraId
- + ", facing " + facing
- + ", isNdk " + e.mIsNdk
- + ", latencyMs " + e.mLatencyMs
- + ", operatingMode " + e.mOperatingMode
- + ", internalReconfigure " + e.mInternalReconfigure
- + ", requestCount " + e.mRequestCount
- + ", resultErrorCount " + e.mResultErrorCount
- + ", deviceError " + e.mDeviceError
- + ", streamCount is " + streamCount
- + ", userTag is " + e.mUserTag
- + ", videoStabilizationMode " + e.mVideoStabilizationMode
- + ultrawideDebug
- + zoomOverrideDebug
- + mostRequestedFpsRangeDebug
- + ", logId " + e.mLogId
- + ", sessionIndex " + e.mSessionIndex
- + ", mExtSessionStats {type " + extensionType
- + " isAdvanced " + extensionIsAdvanced
- + extensionCaptureFormatDebug + "}");
- }
-
- // Convert from CameraStreamStats to CameraStreamProto
- CameraStreamProto[] streamProtos = new CameraStreamProto[MAX_STREAM_STATISTICS];
- for (int i = 0; i < MAX_STREAM_STATISTICS; i++) {
- streamProtos[i] = new CameraStreamProto();
- if (i < streamCount) {
- CameraStreamStats streamStats = e.mStreamStats.get(i);
- streamProtos[i].width = streamStats.getWidth();
- streamProtos[i].height = streamStats.getHeight();
- streamProtos[i].format = streamStats.getFormat();
- streamProtos[i].dataSpace = streamStats.getDataSpace();
- streamProtos[i].usage = streamStats.getUsage();
- streamProtos[i].requestCount = streamStats.getRequestCount();
- streamProtos[i].errorCount = streamStats.getErrorCount();
- streamProtos[i].firstCaptureLatencyMillis = streamStats.getStartLatencyMs();
- streamProtos[i].maxHalBuffers = streamStats.getMaxHalBuffers();
- streamProtos[i].maxAppBuffers = streamStats.getMaxAppBuffers();
- streamProtos[i].histogramType = streamStats.getHistogramType();
- streamProtos[i].histogramBins = streamStats.getHistogramBins();
- streamProtos[i].histogramCounts = streamStats.getHistogramCounts();
- streamProtos[i].dynamicRangeProfile = streamStats.getDynamicRangeProfile();
- streamProtos[i].streamUseCase = streamStats.getStreamUseCase();
- streamProtos[i].colorSpace = streamStats.getColorSpace();
-
- if (CameraServiceProxy.DEBUG) {
- String histogramTypeName =
- cameraHistogramTypeToString(streamProtos[i].histogramType);
- Slog.v(TAG, "Stream " + i + ": width " + streamProtos[i].width
- + ", height " + streamProtos[i].height
- + ", format " + streamProtos[i].format
- + ", maxPreviewFps " + streamStats.getMaxPreviewFps()
- + ", dataSpace " + streamProtos[i].dataSpace
- + ", usage " + streamProtos[i].usage
- + ", requestCount " + streamProtos[i].requestCount
- + ", errorCount " + streamProtos[i].errorCount
- + ", firstCaptureLatencyMillis "
- + streamProtos[i].firstCaptureLatencyMillis
- + ", maxHalBuffers " + streamProtos[i].maxHalBuffers
- + ", maxAppBuffers " + streamProtos[i].maxAppBuffers
- + ", histogramType " + histogramTypeName
- + ", histogramBins "
- + Arrays.toString(streamProtos[i].histogramBins)
- + ", histogramCounts "
- + Arrays.toString(streamProtos[i].histogramCounts)
- + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile
- + ", streamUseCase " + streamProtos[i].streamUseCase
- + ", colorSpace " + streamProtos[i].colorSpace);
- }
- }
- }
- FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_ACTION_EVENT, e.getDuration(),
- e.mAPILevel, e.mClientName, facing, e.mCameraId, e.mAction, e.mIsNdk,
- e.mLatencyMs, e.mOperatingMode, e.mInternalReconfigure,
- e.mRequestCount, e.mResultErrorCount, e.mDeviceError,
- streamCount, MessageNano.toByteArray(streamProtos[0]),
- MessageNano.toByteArray(streamProtos[1]),
- MessageNano.toByteArray(streamProtos[2]),
- MessageNano.toByteArray(streamProtos[3]),
- MessageNano.toByteArray(streamProtos[4]),
- e.mUserTag, e.mVideoStabilizationMode,
- e.mLogId, e.mSessionIndex,
- extensionType, extensionIsAdvanced, e.mUsedUltraWide,
- e.mUsedZoomOverride,
- e.mMostRequestedFpsRange.getLower(), e.mMostRequestedFpsRange.getUpper(),
- extensionCaptureFormat);
- }
}
/**
@@ -1055,22 +1137,22 @@
*/
int getUsageEventCount() {
synchronized (mLock) {
- return mCameraUsageHistory.size();
+ return mCameraEventHistory.size();
}
}
/**
- * Dump camera usage events to log.
+ * Dump camera events to log.
* Package-private
*/
- void dumpUsageEvents() {
+ void dumpCameraEvents() {
synchronized(mLock) {
// Randomize order of events so that it's not meaningful
- Collections.shuffle(mCameraUsageHistory);
+ Collections.shuffle(mCameraEventHistory);
mLogWriterService.execute(new EventWriterTask(
- new ArrayList<CameraUsageEvent>(mCameraUsageHistory)));
+ new ArrayList(mCameraEventHistory)));
- mCameraUsageHistory.clear();
+ mCameraEventHistory.clear();
}
final long ident = Binder.clearCallingIdentity();
try {
@@ -1288,7 +1370,7 @@
cameraId, facing, clientName, apiLevel, isNdk,
FrameworkStatsLog.CAMERA_ACTION_EVENT__ACTION__OPEN,
latencyMs, sessionType, deviceError, logId, sessionIdx);
- mCameraUsageHistory.add(openEvent);
+ mCameraEventHistory.add(openEvent);
break;
case CameraSessionStats.CAMERA_STATE_ACTIVE:
// Check current active camera IDs to see if this package is already talking to
@@ -1323,7 +1405,7 @@
/*userTag*/"", /*videoStabilizationMode*/-1, /*usedUltraWide*/false,
/*usedZoomOverride*/false, new Range<Integer>(0, 0),
new CameraExtensionSessionStats());
- mCameraUsageHistory.add(oldEvent);
+ mCameraEventHistory.add(oldEvent);
}
break;
case CameraSessionStats.CAMERA_STATE_IDLE:
@@ -1335,7 +1417,7 @@
resultErrorCount, deviceError, streamStats, userTag,
videoStabilizationMode, usedUltraWide, usedZoomOverride,
mostRequestedFpsRange, extSessionStats);
- mCameraUsageHistory.add(doneEvent);
+ mCameraEventHistory.add(doneEvent);
// Do not double count device error
deviceError = false;
@@ -1362,11 +1444,11 @@
cameraId, facing, clientName, apiLevel, isNdk,
FrameworkStatsLog.CAMERA_ACTION_EVENT__ACTION__CLOSE,
latencyMs, sessionType, deviceError, logId, sessionIdx);
- mCameraUsageHistory.add(closeEvent);
+ mCameraEventHistory.add(closeEvent);
}
- if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) {
- dumpUsageEvents();
+ if (mCameraEventHistory.size() > MAX_USAGE_HISTORY) {
+ dumpCameraEvents();
}
break;
@@ -1378,6 +1460,18 @@
}
}
+ private void updateFeatureCombinationQuery(CameraFeatureCombinationStats featureCombStats) {
+ synchronized (mLock) {
+ CameraFeatureCombinationQueryEvent e =
+ new CameraFeatureCombinationQueryEvent(featureCombStats);
+ mCameraEventHistory.add(e);
+
+ if (mCameraEventHistory.size() > MAX_USAGE_HISTORY) {
+ dumpCameraEvents();
+ }
+ }
+ }
+
private void notifyNfcService(boolean enablePolling) {
NfcManager nfcManager = mContext.getSystemService(NfcManager.class);
if (nfcManager == null) {
@@ -1434,4 +1528,41 @@
return "HISTOGRAM_TYPE_UNKNOWN";
}
+ private static String cameraFeatureCombinationTypeToString(int featureCombinationType) {
+ switch (featureCombinationType) {
+ case CameraFeatureCombinationStats.QueryType.QUERY_FEATURE_COMBINATION:
+ return "QUERY_FEATURE_COMBINATION";
+ case CameraFeatureCombinationStats.QueryType.QUERY_SESSION_CHARACTERISTICS:
+ return "QUERY_SESSION_CHARACTERISTICS";
+ default:
+ break;
+ }
+ return "FEATURE_COMBINATION_TYPE_UNKNOWN";
+ }
+
+ private static String cameraFeatureCombinationToString(long featureCombination) {
+ StringBuilder combinationStr = new StringBuilder("{");
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_60_FPS) != 0) {
+ combinationStr.append("60fps ");
+ }
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_STABILIZATION)
+ != 0) {
+ combinationStr.append("stabilization ");
+ }
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_HLG10) != 0) {
+ combinationStr.append("hlg10 ");
+ }
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_JPEG) != 0) {
+ combinationStr.append("jpeg ");
+ }
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_JPEG_R) != 0) {
+ combinationStr.append("jpeg_r ");
+ }
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_4K) != 0) {
+ combinationStr.append("4k ");
+ }
+ combinationStr.append("}");
+
+ return combinationStr.toString();
+ }
}
diff --git a/services/core/java/com/android/server/camera/CameraStatsJobService.java b/services/core/java/com/android/server/camera/CameraStatsJobService.java
index b8a6846..1227ca7 100644
--- a/services/core/java/com/android/server/camera/CameraStatsJobService.java
+++ b/services/core/java/com/android/server/camera/CameraStatsJobService.java
@@ -21,14 +21,13 @@
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.util.Slog;
-import java.util.concurrent.TimeUnit;
-
import com.android.server.LocalServices;
+import java.util.concurrent.TimeUnit;
+
/**
* A JobService to periodically collect camera usage stats.
*/
@@ -50,7 +49,7 @@
return false;
}
- serviceProxy.dumpUsageEvents();
+ serviceProxy.dumpCameraEvents();
return false;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 3d75c48..9e8bf0e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -17,6 +17,7 @@
package com.android.server.inputmethod;
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
+import static android.content.Context.DEVICE_ID_DEFAULT;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.INVALID_DISPLAY;
@@ -91,6 +92,7 @@
/** The display id for which the latest startInput was called. */
@GuardedBy("ImfLock.class") private int mDisplayIdToShowIme = INVALID_DISPLAY;
+ @GuardedBy("ImfLock.class") private int mDeviceIdToShowIme = DEVICE_ID_DEFAULT;
@Nullable private CountDownLatch mLatchForTesting;
@@ -609,4 +611,14 @@
int getDisplayIdToShowIme() {
return mDisplayIdToShowIme;
}
+
+ @GuardedBy("ImfLock.class")
+ void setDeviceIdToShowIme(int deviceId) {
+ mDeviceIdToShowIme = deviceId;
+ }
+
+ @GuardedBy("ImfLock.class")
+ int getDeviceIdToShowIme() {
+ return mDeviceIdToShowIme;
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1a0ffb7..6b15bce 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -382,10 +382,6 @@
@MultiUserUnawareField
private HardwareKeyboardShortcutController mHardwareKeyboardShortcutController;
- @GuardedBy("ImfLock.class")
- @MultiUserUnawareField
- private int mDeviceIdToShowIme = DEVICE_ID_DEFAULT;
-
@Nullable
private StatusBarManagerInternal mStatusBarManagerInternal;
@SharedByAllUsersField
@@ -2143,7 +2139,8 @@
if (deviceMethodId == null) {
mVisibilityStateComputer.getImePolicy().setImeHiddenByDisplayPolicy(true);
} else if (!Objects.equals(deviceMethodId, selectedMethodId)) {
- setInputMethodLocked(deviceMethodId, NOT_A_SUBTYPE_ID, mDeviceIdToShowIme);
+ setInputMethodLocked(deviceMethodId, NOT_A_SUBTYPE_ID,
+ bindingController.getDeviceIdToShowIme());
selectedMethodId = deviceMethodId;
}
@@ -2256,11 +2253,12 @@
}
final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
- final int oldDeviceId = mDeviceIdToShowIme;
final var bindingController = getInputMethodBindingController(userId);
+ final int oldDeviceId = bindingController.getDeviceIdToShowIme();
final int displayIdToShowIme = bindingController.getDisplayIdToShowIme();
- mDeviceIdToShowIme = mVdmInternal.getDeviceIdForDisplayId(displayIdToShowIme);
- if (mDeviceIdToShowIme == DEVICE_ID_DEFAULT) {
+ final int newDeviceId = mVdmInternal.getDeviceIdForDisplayId(displayIdToShowIme);
+ bindingController.setDeviceIdToShowIme(newDeviceId);
+ if (newDeviceId == DEVICE_ID_DEFAULT) {
if (oldDeviceId == DEVICE_ID_DEFAULT) {
return currentMethodId;
}
@@ -2272,13 +2270,12 @@
return defaultDeviceMethodId;
}
- final String deviceMethodId =
- mVirtualDeviceMethodMap.get(mDeviceIdToShowIme, currentMethodId);
+ final String deviceMethodId = mVirtualDeviceMethodMap.get(newDeviceId, currentMethodId);
if (Objects.equals(deviceMethodId, currentMethodId)) {
return currentMethodId;
} else if (!settings.getMethodMap().containsKey(deviceMethodId)) {
if (DEBUG) {
- Slog.v(TAG, "Disabling IME on virtual device with id " + mDeviceIdToShowIme
+ Slog.v(TAG, "Disabling IME on virtual device with id " + newDeviceId
+ " because its custom input method is not available: " + deviceMethodId);
}
return null;
@@ -2293,7 +2290,7 @@
if (DEBUG) {
Slog.v(TAG, "Switching current input method from " + currentMethodId
+ " to device-specific one " + deviceMethodId + " because the current display "
- + displayIdToShowIme + " belongs to device with id " + mDeviceIdToShowIme);
+ + displayIdToShowIme + " belongs to device with id " + newDeviceId);
}
return deviceMethodId;
}
@@ -2934,7 +2931,7 @@
* <li>
* {@link PackageManager#COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED} is not updated.
* </li>
- * <li>{@link #mDeviceIdToShowIme} is ignored.</li>
+ * <li>{@link InputMethodBindingController#getDeviceIdToShowIme()} is ignored.</li>
* <li>{@link #mSwitchingController} is ignored.</li>
* <li>{@link #mHardwareKeyboardShortcutController} is ignored.</li>
* <li>{@link #mPreventImeStartupUnlessTextEditor} is ignored.</li>
@@ -3004,7 +3001,8 @@
}
}
- if (mDeviceIdToShowIme == DEVICE_ID_DEFAULT) {
+ final var bindingController = getInputMethodBindingController(mCurrentUserId);
+ if (bindingController.getDeviceIdToShowIme() == DEVICE_ID_DEFAULT) {
String ime = SecureSettingsWrapper.getString(
Settings.Secure.DEFAULT_INPUT_METHOD, null, userId);
String defaultDeviceIme = SecureSettingsWrapper.getString(
@@ -3122,8 +3120,10 @@
return;
}
+ final var bindingController = getInputMethodBindingController(userId);
// Changing to a different IME.
- if (mDeviceIdToShowIme != DEVICE_ID_DEFAULT && deviceId == DEVICE_ID_DEFAULT) {
+ if (bindingController.getDeviceIdToShowIme() != DEVICE_ID_DEFAULT
+ && deviceId == DEVICE_ID_DEFAULT) {
// This change should only be applicable to the default device but the current input
// method is a custom one specific to a virtual device. So only update the settings
// entry used to restore the default device input method once we want to show the IME
@@ -5382,7 +5382,8 @@
*/
@GuardedBy("ImfLock.class")
private boolean setInputMethodEnabledLocked(String id, boolean enabled) {
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
+ final int userId = mCurrentUserId;
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
if (enabled) {
final String enabledImeIdsStr = settings.getEnabledInputMethodsStr();
final String newEnabledImeIdsStr = InputMethodUtils.concatEnabledImeIds(
@@ -5401,7 +5402,8 @@
StringBuilder builder = new StringBuilder();
if (settings.buildAndPutEnabledInputMethodsStrRemovingId(
builder, enabledInputMethodsList, id)) {
- if (mDeviceIdToShowIme == DEVICE_ID_DEFAULT) {
+ final var bindingController = getInputMethodBindingController(userId);
+ if (bindingController.getDeviceIdToShowIme() == DEVICE_ID_DEFAULT) {
// Disabled input method is currently selected, switch to another one.
final String selId = settings.getSelectedInputMethod();
if (id.equals(selId) && !chooseNewDefaultIMELocked()) {
@@ -5459,9 +5461,9 @@
@GuardedBy("ImfLock.class")
private void resetSelectedInputMethodAndSubtypeLocked(String newDefaultIme) {
- mDeviceIdToShowIme = DEVICE_ID_DEFAULT;
final var bindingController = getInputMethodBindingController(mCurrentUserId);
bindingController.setDisplayIdToShowIme(INVALID_DISPLAY);
+ bindingController.setDeviceIdToShowIme(DEVICE_ID_DEFAULT);
final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
settings.putSelectedDefaultDeviceInputMethod(null);
@@ -5518,44 +5520,18 @@
*/
@GuardedBy("ImfLock.class")
InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
- String selectedMethodId = getSelectedMethodIdLocked();
+ final int userId = mCurrentUserId;
+ final var selectedMethodId = getInputMethodBindingController(userId).getSelectedMethodId();
if (selectedMethodId == null) {
return null;
}
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
- final boolean subtypeIsSelected = settings.isSubtypeSelected();
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
final InputMethodInfo imi = settings.getMethodMap().get(selectedMethodId);
if (imi == null || imi.getSubtypeCount() == 0) {
return null;
}
- if (!subtypeIsSelected || mCurrentSubtype == null
- || !SubtypeUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
- int subtypeId = settings.getSelectedInputMethodSubtypeId(selectedMethodId);
- if (subtypeId == NOT_A_SUBTYPE_ID) {
- // If there are no selected subtypes, the framework will try to find
- // the most applicable subtype from explicitly or implicitly enabled
- // subtypes.
- List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
- settings.getEnabledInputMethodSubtypeList(imi, true);
- // If there is only one explicitly or implicitly enabled subtype,
- // just returns it.
- if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
- mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
- } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
- final String locale = SystemLocaleWrapper.get(settings.getUserId())
- .get(0).toString();
- mCurrentSubtype = SubtypeUtils.findLastResortApplicableSubtype(
- explicitlyOrImplicitlyEnabledSubtypes,
- SubtypeUtils.SUBTYPE_MODE_KEYBOARD, locale, true);
- if (mCurrentSubtype == null) {
- mCurrentSubtype = SubtypeUtils.findLastResortApplicableSubtype(
- explicitlyOrImplicitlyEnabledSubtypes, null, locale, true);
- }
- }
- } else {
- mCurrentSubtype = SubtypeUtils.getSubtypes(imi).get(subtypeId);
- }
- }
+ mCurrentSubtype = SubtypeUtils.getCurrentInputMethodSubtype(imi, settings,
+ mCurrentSubtype);
return mCurrentSubtype;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSettings.java b/services/core/java/com/android/server/inputmethod/InputMethodSettings.java
index a558838..7ce4074 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSettings.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSettings.java
@@ -51,8 +51,23 @@
public static final boolean DEBUG = false;
private static final String TAG = "InputMethodSettings";
- private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
- private static final String NOT_A_SUBTYPE_ID_STR = String.valueOf(NOT_A_SUBTYPE_ID);
+ /**
+ * An integer code that represents "no subtype" when a subtype hashcode is used.
+ *
+ * <p>Due to historical confusions with {@link InputMethodUtils#NOT_A_SUBTYPE_ID}, we have
+ * used {@code -1} here. We cannot change this value as it's already saved into secure settings.
+ * </p>
+ */
+ private static final int INVALID_SUBTYPE_HASHCODE = -1;
+ /**
+ * A string code that represents "no subtype" when a subtype hashcode is used.
+ *
+ * <p>Due to historical confusions with {@link InputMethodUtils#NOT_A_SUBTYPE_ID}, we have
+ * used {@code "-1"} here. We cannot change this value as it's already saved into secure
+ * settings.</p>
+ */
+ private static final String INVALID_SUBTYPE_HASHCODE_STR =
+ String.valueOf(INVALID_SUBTYPE_HASHCODE);
private static final char INPUT_METHOD_SEPARATOR = InputMethodUtils.INPUT_METHOD_SEPARATOR;
private static final char INPUT_METHOD_SUBTYPE_SEPARATOR =
InputMethodUtils.INPUT_METHOD_SUBTYPE_SEPARATOR;
@@ -259,34 +274,33 @@
}
private void saveSubtypeHistory(
- List<Pair<String, String>> savedImes, String newImeId, String newSubtypeId) {
+ List<Pair<String, String>> savedImes, String newImeId, String newSubtypeHashCodeStr) {
final StringBuilder builder = new StringBuilder();
boolean isImeAdded = false;
- if (!TextUtils.isEmpty(newImeId) && !TextUtils.isEmpty(newSubtypeId)) {
+ if (!TextUtils.isEmpty(newImeId) && !TextUtils.isEmpty(newSubtypeHashCodeStr)) {
builder.append(newImeId).append(INPUT_METHOD_SUBTYPE_SEPARATOR).append(
- newSubtypeId);
+ newSubtypeHashCodeStr);
isImeAdded = true;
}
for (int i = 0; i < savedImes.size(); ++i) {
final Pair<String, String> ime = savedImes.get(i);
final String imeId = ime.first;
- String subtypeId = ime.second;
- if (TextUtils.isEmpty(subtypeId)) {
- subtypeId = NOT_A_SUBTYPE_ID_STR;
+ String subtypeHashCodeStr = ime.second;
+ if (TextUtils.isEmpty(subtypeHashCodeStr)) {
+ subtypeHashCodeStr = INVALID_SUBTYPE_HASHCODE_STR;
}
if (isImeAdded) {
builder.append(INPUT_METHOD_SEPARATOR);
} else {
isImeAdded = true;
}
- builder.append(imeId).append(INPUT_METHOD_SUBTYPE_SEPARATOR).append(
- subtypeId);
+ builder.append(imeId).append(INPUT_METHOD_SUBTYPE_SEPARATOR).append(subtypeHashCodeStr);
}
// Remove the last INPUT_METHOD_SEPARATOR
putSubtypeHistoryStr(builder.toString());
}
- private void addSubtypeToHistory(String imeId, String subtypeId) {
+ private void addSubtypeToHistory(String imeId, String subtypeHashCodeStr) {
final List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistory();
for (int i = 0; i < subtypeHistory.size(); ++i) {
final Pair<String, String> ime = subtypeHistory.get(i);
@@ -301,9 +315,9 @@
}
}
if (DEBUG) {
- Slog.v(TAG, "Add subtype to the history: " + imeId + ", " + subtypeId);
+ Slog.v(TAG, "Add subtype to the history: " + imeId + ", " + subtypeHashCodeStr);
}
- saveSubtypeHistory(subtypeHistory, imeId, subtypeId);
+ saveSubtypeHistory(subtypeHistory, imeId, subtypeHashCodeStr);
}
private void putSubtypeHistoryStr(@NonNull String str) {
@@ -413,26 +427,26 @@
for (int j = 0; j < explicitlyEnabledSubtypes.size(); ++j) {
final String s = explicitlyEnabledSubtypes.get(j);
if (s.equals(subtypeHashCode)) {
- // If both imeId and subtypeId are enabled, return subtypeId.
+ // If both imeId and subtype are enabled, return subtypeId.
try {
final int hashCode = Integer.parseInt(subtypeHashCode);
- // Check whether the subtype id is valid or not
- if (SubtypeUtils.isValidSubtypeId(imi, hashCode)) {
+ // Check whether the subtype is valid or not
+ if (SubtypeUtils.isValidSubtypeHashCode(imi, hashCode)) {
return s;
} else {
- return NOT_A_SUBTYPE_ID_STR;
+ return INVALID_SUBTYPE_HASHCODE_STR;
}
} catch (NumberFormatException e) {
- return NOT_A_SUBTYPE_ID_STR;
+ return INVALID_SUBTYPE_HASHCODE_STR;
}
}
}
}
- // If imeId was enabled but subtypeId was disabled.
- return NOT_A_SUBTYPE_ID_STR;
+ // If imeId was enabled but subtype was disabled.
+ return INVALID_SUBTYPE_HASHCODE_STR;
}
}
- // If both imeId and subtypeId are disabled, return null
+ // If both imeId and subtype are disabled, return null
return null;
}
@@ -451,14 +465,14 @@
String nextImsStr = inputMethodSplitter.next();
subtypeSplitter.setString(nextImsStr);
if (subtypeSplitter.hasNext()) {
- String subtypeId = NOT_A_SUBTYPE_ID_STR;
+ String subtypeHashCodeStr = INVALID_SUBTYPE_HASHCODE_STR;
// The first element is ime id.
String imeId = subtypeSplitter.next();
while (subtypeSplitter.hasNext()) {
- subtypeId = subtypeSplitter.next();
+ subtypeHashCodeStr = subtypeSplitter.next();
break;
}
- imsList.add(new Pair<>(imeId, subtypeId));
+ imsList.add(new Pair<>(imeId, subtypeHashCodeStr));
}
}
return imsList;
@@ -528,13 +542,8 @@
return imi;
}
- boolean isSubtypeSelected() {
- return getSelectedInputMethodSubtypeHashCode() != NOT_A_SUBTYPE_ID;
- }
-
private int getSelectedInputMethodSubtypeHashCode() {
- return getInt(Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
- NOT_A_SUBTYPE_ID);
+ return getInt(Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, INVALID_SUBTYPE_HASHCODE);
}
@UserIdInt
@@ -545,7 +554,7 @@
int getSelectedInputMethodSubtypeId(String selectedImiId) {
final InputMethodInfo imi = mMethodMap.get(selectedImiId);
if (imi == null) {
- return NOT_A_SUBTYPE_ID;
+ return InputMethodUtils.NOT_A_SUBTYPE_ID;
}
final int subtypeHashCode = getSelectedInputMethodSubtypeHashCode();
return SubtypeUtils.getSubtypeIdFromHashCode(imi, subtypeHashCode);
@@ -553,12 +562,12 @@
void saveCurrentInputMethodAndSubtypeToHistory(String curMethodId,
InputMethodSubtype currentSubtype) {
- String subtypeId = NOT_A_SUBTYPE_ID_STR;
+ String subtypeHashCodeStr = INVALID_SUBTYPE_HASHCODE_STR;
if (currentSubtype != null) {
- subtypeId = String.valueOf(currentSubtype.hashCode());
+ subtypeHashCodeStr = String.valueOf(currentSubtype.hashCode());
}
if (InputMethodUtils.canAddToLastInputMethod(currentSubtype)) {
- addSubtypeToHistory(curMethodId, subtypeId);
+ addSubtypeToHistory(curMethodId, subtypeHashCodeStr);
}
}
@@ -583,7 +592,7 @@
}
final int subtypeHashCode = getSelectedInputMethodSubtypeHashCode();
- if (subtypeHashCode != NOT_A_SUBTYPE_ID) {
+ if (subtypeHashCode != INVALID_SUBTYPE_HASHCODE) {
final int subtypeIndex = SubtypeUtils.getSubtypeIdFromHashCode(imi,
subtypeHashCode);
if (subtypeIndex >= 0) {
@@ -645,10 +654,10 @@
final IntArray validSubtypeHashCodes = new IntArray(subtypeHashCodes.length);
for (int subtypeHashCode : subtypeHashCodes) {
- if (subtypeHashCode == NOT_A_SUBTYPE_ID) {
- continue; // NOT_A_SUBTYPE_ID must not be saved
+ if (subtypeHashCode == INVALID_SUBTYPE_HASHCODE) {
+ continue; // INVALID_SUBTYPE_HASHCODE must not be saved
}
- if (!SubtypeUtils.isValidSubtypeId(imi, subtypeHashCode)) {
+ if (!SubtypeUtils.isValidSubtypeHashCode(imi, subtypeHashCode)) {
continue; // this subtype does not exist in InputMethodInfo.
}
if (validSubtypeHashCodes.indexOf(subtypeHashCode) >= 0) {
diff --git a/services/core/java/com/android/server/inputmethod/SubtypeUtils.java b/services/core/java/com/android/server/inputmethod/SubtypeUtils.java
index 3d5c8677..1b4c0d6 100644
--- a/services/core/java/com/android/server/inputmethod/SubtypeUtils.java
+++ b/services/core/java/com/android/server/inputmethod/SubtypeUtils.java
@@ -16,9 +16,11 @@
package com.android.server.inputmethod;
+import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.LocaleList;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
@@ -100,7 +102,7 @@
return subtypes;
}
- static boolean isValidSubtypeId(InputMethodInfo imi, int subtypeHashCode) {
+ static boolean isValidSubtypeHashCode(InputMethodInfo imi, int subtypeHashCode) {
return getSubtypeIdFromHashCode(imi, subtypeHashCode) != NOT_A_SUBTYPE_ID;
}
@@ -289,4 +291,54 @@
}
return applicableSubtype;
}
+
+ /**
+ * Returns a {@link InputMethodSubtype} available in {@code imi} based on
+ * {@link Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE}.
+ *
+ * @param imi {@link InputMethodInfo} to find out the current
+ * {@link InputMethodSubtype}
+ * @param settings {@link InputMethodSettings} to be used to find out the current
+ * {@link InputMethodSubtype}
+ * @param currentSubtype the current value that will be used as fallback
+ * @return {@link InputMethodSubtype} to be used as the current {@link InputMethodSubtype}
+ */
+ @AnyThread
+ @Nullable
+ static InputMethodSubtype getCurrentInputMethodSubtype(
+ @NonNull InputMethodInfo imi, @NonNull InputMethodSettings settings,
+ @Nullable InputMethodSubtype currentSubtype) {
+ final int userId = settings.getUserId();
+ final int selectedSubtypeHashCode = SecureSettingsWrapper.getInt(
+ Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, NOT_A_SUBTYPE_ID, userId);
+ if (selectedSubtypeHashCode != NOT_A_SUBTYPE_ID && currentSubtype != null
+ && isValidSubtypeHashCode(imi, currentSubtype.hashCode())) {
+ return currentSubtype;
+ }
+
+ final int subtypeId = settings.getSelectedInputMethodSubtypeId(imi.getId());
+ if (subtypeId != NOT_A_SUBTYPE_ID) {
+ return imi.getSubtypeAt(subtypeId);
+ }
+
+ // If there are no selected subtypes, the framework will try to find the most applicable
+ // subtype from explicitly or implicitly enabled subtypes.
+ final List<InputMethodSubtype> subtypes = settings.getEnabledInputMethodSubtypeList(imi,
+ true);
+ if (subtypes.isEmpty()) {
+ return currentSubtype;
+ }
+ // If there is only one explicitly or implicitly enabled subtype,
+ // just returns it.
+ if (subtypes.size() == 1) {
+ return subtypes.get(0);
+ }
+ final String locale = SystemLocaleWrapper.get(userId).get(0).toString();
+ final var subtype = findLastResortApplicableSubtype(subtypes, SUBTYPE_MODE_KEYBOARD, locale,
+ true);
+ if (subtype != null) {
+ return subtype;
+ }
+ return findLastResortApplicableSubtype(subtypes, null, locale, true);
+ }
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index f03c639..d9e22c5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -28,6 +28,7 @@
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManager.isProcStateConsideredInteraction;
import static android.app.ActivityManager.printCapabilitiesSummary;
@@ -523,6 +524,12 @@
*/
private boolean mUseMeteredFirewallChains;
+ /**
+ * Whether or not sensitive process states and non-sensitive process-states have different
+ * delays before network is blocked after transitioning to background.
+ */
+ private boolean mUseDifferentDelaysForBackgroundChain;
+
// See main javadoc for instructions on how to use these locks.
final Object mUidRulesFirstLock = new Object();
final Object mNetworkPoliciesSecondLock = new Object();
@@ -552,10 +559,43 @@
* {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} will lose network access.
* The delay is meant to prevent churn due to quick process-state changes.
* Note that there is no delay while granting network access.
+ *
+ * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is disabled.
*/
@VisibleForTesting
long mBackgroundRestrictionDelayMs = TimeUnit.SECONDS.toMillis(5);
+ /**
+ * Short delay after which a uid going into a process state having priority equal to
+ * {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} or lower will lose network access.
+ *
+ * This will apply to apps that should be fine with losing network access immediately.
+ * It is only meant as a debounce to prevent churn due to quick process-state changes.
+ * Note that there is no delay while granting network access.
+ *
+ * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is enabled.
+ */
+ @VisibleForTesting
+ long mBackgroundRestrictionShortDelayMs = TimeUnit.SECONDS.toMillis(2);
+
+ /**
+ * Long delay after which a uid going into a process state having priority equal to
+ * {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} or lower will lose network access.
+ *
+ * Unlike {@link #mBackgroundRestrictionShortDelayMs}, this is meant to be applied to apps
+ * in sensitive proc-states like {@link ActivityManager#PROCESS_STATE_TOP_SLEEPING} and
+ * {@link ActivityManager#PROCESS_STATE_LAST_ACTIVITY}, where the user may switch to this app
+ * before this period and any latency in granting network access before resuming app activities
+ * may degrade experience.
+ *
+ * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is enabled.
+ */
+ @VisibleForTesting
+ long mBackgroundRestrictionLongDelayMs = TimeUnit.SECONDS.toMillis(20);
+
+ @GuardedBy("mUidRulesFirstLock")
+ private long mNextProcessBackgroundUidsTime = Long.MAX_VALUE;
+
/** Defined network policies. */
@GuardedBy("mNetworkPoliciesSecondLock")
final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>();
@@ -1007,6 +1047,7 @@
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mUseMeteredFirewallChains = Flags.useMeteredFirewallChains();
+ mUseDifferentDelaysForBackgroundChain = Flags.useDifferentDelaysForBackgroundChain();
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
@@ -1241,11 +1282,21 @@
// different chains may change.
return true;
}
- if (mBackgroundNetworkRestricted && (previousProcState >= BACKGROUND_THRESHOLD_STATE)
+ if (mBackgroundNetworkRestricted) {
+ if ((previousProcState >= BACKGROUND_THRESHOLD_STATE)
!= (newProcState >= BACKGROUND_THRESHOLD_STATE)) {
- // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: Network rules for the
- // BACKGROUND chain may change.
- return true;
+ // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: The network rules will
+ // need to be re-evaluated for the background chain.
+ return true;
+ }
+ if (mUseDifferentDelaysForBackgroundChain
+ && newProcState >= BACKGROUND_THRESHOLD_STATE
+ && getBackgroundTransitioningDelay(newProcState)
+ < getBackgroundTransitioningDelay(previousProcState)) {
+ // The old and new proc-state both are in the blocked state but the background
+ // transition delay is reduced, so we may have to update the rules sooner.
+ return true;
+ }
}
final int networkCapabilities = PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
| PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
@@ -4045,6 +4096,8 @@
+ mBackgroundNetworkRestricted);
fout.println(Flags.FLAG_USE_METERED_FIREWALL_CHAINS + ": "
+ mUseMeteredFirewallChains);
+ fout.println(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN + ": "
+ + mUseDifferentDelaysForBackgroundChain);
fout.println();
fout.println("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
@@ -4188,20 +4241,34 @@
fout.decreaseIndent();
}
- size = mBackgroundTransitioningUids.size();
- if (size > 0) {
- final long nowUptime = SystemClock.uptimeMillis();
- fout.println("Uids transitioning to background:");
- fout.increaseIndent();
- for (int i = 0; i < size; i++) {
- fout.print("UID=");
- fout.print(mBackgroundTransitioningUids.keyAt(i));
- fout.print(", ");
- TimeUtils.formatDuration(mBackgroundTransitioningUids.valueAt(i), nowUptime,
- fout);
+ if (mBackgroundNetworkRestricted) {
+ fout.println();
+ if (mUseDifferentDelaysForBackgroundChain) {
+ fout.print("Background restrictions short delay: ");
+ TimeUtils.formatDuration(mBackgroundRestrictionShortDelayMs, fout);
+ fout.println();
+
+ fout.print("Background restrictions long delay: ");
+ TimeUtils.formatDuration(mBackgroundRestrictionLongDelayMs, fout);
fout.println();
}
- fout.decreaseIndent();
+
+ size = mBackgroundTransitioningUids.size();
+ if (size > 0) {
+ final long nowUptime = SystemClock.uptimeMillis();
+ fout.println("Uids transitioning to background:");
+ fout.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ fout.print("UID=");
+ fout.print(mBackgroundTransitioningUids.keyAt(i));
+ fout.print(", ");
+ TimeUtils.formatDuration(mBackgroundTransitioningUids.valueAt(i),
+ nowUptime, fout);
+ fout.println();
+ }
+ fout.decreaseIndent();
+ }
+ fout.println();
}
final SparseBooleanArray knownUids = new SparseBooleanArray();
@@ -4337,6 +4404,15 @@
|| isProcStateAllowedNetworkWhileBackground(mUidState.get(uid));
}
+ private long getBackgroundTransitioningDelay(int procState) {
+ if (mUseDifferentDelaysForBackgroundChain) {
+ return procState <= PROCESS_STATE_LAST_ACTIVITY ? mBackgroundRestrictionLongDelayMs
+ : mBackgroundRestrictionShortDelayMs;
+ } else {
+ return mBackgroundRestrictionDelayMs;
+ }
+ }
+
/**
* Process state of UID changed; if needed, will trigger
* {@link #updateRulesForDataUsageRestrictionsUL(int)} and
@@ -4387,19 +4463,41 @@
mBackgroundTransitioningUids.delete(uid);
updateRuleForBackgroundUL(uid);
updatePowerRestrictionRules = true;
- } else if (wasAllowed && !isAllowed) {
+ } else if (!isAllowed) {
+ final int transitionIdx = mBackgroundTransitioningUids.indexOfKey(uid);
final long completionTimeMs = SystemClock.uptimeMillis()
- + mBackgroundRestrictionDelayMs;
- if (mBackgroundTransitioningUids.indexOfKey(uid) < 0) {
- // This is just a defensive check in case the upstream code ever makes
- // multiple calls for the same process state change.
- mBackgroundTransitioningUids.put(uid, completionTimeMs);
+ + getBackgroundTransitioningDelay(procState);
+ boolean completionTimeUpdated = false;
+ if (wasAllowed) {
+ // Rules need to transition from allowed to blocked after the respective
+ // delay.
+ if (transitionIdx < 0) {
+ // This is just a defensive check in case the upstream code ever
+ // makes multiple calls for the same process state change.
+ mBackgroundTransitioningUids.put(uid, completionTimeMs);
+ completionTimeUpdated = true;
+ }
+ } else if (mUseDifferentDelaysForBackgroundChain) {
+ // wasAllowed was false, but the transition delay may have reduced.
+ // Currently, this can happen when the uid transitions from
+ // LAST_ACTIVITY to CACHED_ACTIVITY, for example.
+ if (transitionIdx >= 0
+ && completionTimeMs < mBackgroundTransitioningUids.valueAt(
+ transitionIdx)) {
+ mBackgroundTransitioningUids.setValueAt(transitionIdx,
+ completionTimeMs);
+ completionTimeUpdated = true;
+ }
}
- if (!mHandler.hasMessages(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS)) {
- // Many uids may be in this "transitioning" state at the same time, so
- // using one message at a time to avoid congestion in the MessageQueue.
+ if (completionTimeUpdated
+ && completionTimeMs < mNextProcessBackgroundUidsTime) {
+ // Many uids may be in this "transitioning" state at the same time,
+ // so we always keep one message to process transition completion at
+ // the earliest time.
+ mHandler.removeMessages(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS);
mHandler.sendEmptyMessageAtTime(
MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, completionTimeMs);
+ mNextProcessBackgroundUidsTime = completionTimeMs;
}
}
}
@@ -5750,10 +5848,11 @@
updateRuleForBackgroundUL(uid);
updateRulesForPowerRestrictionsUL(uid, false);
}
- }
- if (nextCheckTime < Long.MAX_VALUE) {
- mHandler.sendEmptyMessageAtTime(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS,
- nextCheckTime);
+ mNextProcessBackgroundUidsTime = nextCheckTime;
+ if (nextCheckTime < Long.MAX_VALUE) {
+ mHandler.sendEmptyMessageAtTime(
+ MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, nextCheckTime);
+ }
}
return true;
}
diff --git a/services/core/java/com/android/server/net/flags.aconfig b/services/core/java/com/android/server/net/flags.aconfig
index e986dd8..586baf0 100644
--- a/services/core/java/com/android/server/net/flags.aconfig
+++ b/services/core/java/com/android/server/net/flags.aconfig
@@ -17,3 +17,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "use_different_delays_for_background_chain"
+ namespace: "backstage_power"
+ description: "Grant longer grace periods for sensitive process-states before blocking network using the background chain"
+ bug: "323963467"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 60147ef..a8adc06 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -284,6 +284,7 @@
import android.service.notification.NotificationServiceDumpProto;
import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
+import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeProto;
import android.service.notification.ZenPolicy;
@@ -5508,6 +5509,14 @@
}
@Override
+ public void setManualZenRuleDeviceEffects(ZenDeviceEffects effects) throws RemoteException {
+ checkCallerIsSystem();
+
+ mZenModeHelper.setManualZenRuleDeviceEffects(effects, computeZenOrigin(true),
+ "Update manual mode non-policy settings", Binder.getCallingUid());
+ }
+
+ @Override
public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule,
boolean fromUser) throws RemoteException {
validateAutomaticZenRule(id, automaticZenRule);
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 86aa2d8..02b5f97 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -68,16 +68,17 @@
public void evaluateConfig(ZenModeConfig config, ComponentName trigger,
boolean processSubscriptions) {
if (config == null) return;
- if (config.manualRule != null && config.manualRule.condition != null
+ if (!android.app.Flags.modesUi() && config.manualRule != null
+ && config.manualRule.condition != null
&& !config.manualRule.isTrueOrUnknown()) {
if (DEBUG) Log.d(TAG, "evaluateConfig: clearing manual rule");
config.manualRule = null;
}
final ArraySet<Uri> current = new ArraySet<>();
- evaluateRule(config.manualRule, current, null, processSubscriptions);
+ evaluateRule(config.manualRule, current, null, processSubscriptions, true);
for (ZenRule automaticRule : config.automaticRules.values()) {
if (automaticRule.component != null) {
- evaluateRule(automaticRule, current, trigger, processSubscriptions);
+ evaluateRule(automaticRule, current, trigger, processSubscriptions, false);
updateSnoozing(automaticRule);
}
}
@@ -131,7 +132,7 @@
// Only valid for CPS backed rules
private void evaluateRule(ZenRule rule, ArraySet<Uri> current, ComponentName trigger,
- boolean processSubscriptions) {
+ boolean processSubscriptions, boolean isManual) {
if (rule == null || rule.conditionId == null) return;
if (rule.configurationActivity != null) return;
final Uri id = rule.conditionId;
@@ -153,8 +154,10 @@
}
// empty rule? disable and bail early
if (rule.component == null && rule.enabler == null) {
- Log.w(TAG, "No component found for automatic rule: " + rule.conditionId);
- rule.enabled = false;
+ if (!android.app.Flags.modesUi() || (android.app.Flags.modesUi() && !isManual)) {
+ Log.w(TAG, "No component found for automatic rule: " + rule.conditionId);
+ rule.enabled = false;
+ }
return;
}
if (current != null) {
diff --git a/services/core/java/com/android/server/notification/ZenModeEventLogger.java b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
index 418eacc..ec5d96d 100644
--- a/services/core/java/com/android/server/notification/ZenModeEventLogger.java
+++ b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
@@ -18,8 +18,8 @@
import static android.app.NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND;
import static android.provider.Settings.Global.ZEN_MODE_OFF;
-import static android.service.notification.NotificationServiceProto.CHANNEL_POLICY_PRIORITY;
import static android.service.notification.NotificationServiceProto.CHANNEL_POLICY_NONE;
+import static android.service.notification.NotificationServiceProto.CHANNEL_POLICY_PRIORITY;
import static android.service.notification.NotificationServiceProto.RULE_TYPE_AUTOMATIC;
import static android.service.notification.NotificationServiceProto.RULE_TYPE_MANUAL;
import static android.service.notification.NotificationServiceProto.RULE_TYPE_UNKNOWN;
@@ -352,8 +352,10 @@
ZenModeDiff.RuleDiff manualDiff = diff.getManualRuleDiff();
if (manualDiff != null && manualDiff.hasDiff()) {
// a diff in the manual rule doesn't *necessarily* mean that it's responsible for
- // the change -- only if it's been added or removed.
- if (manualDiff.wasAdded() || manualDiff.wasRemoved()) {
+ // the change -- only if it's been added or removed or updated.
+ if (manualDiff.wasAdded() || manualDiff.wasRemoved()
+ || (Flags.modesUi()
+ && (manualDiff.becameActive() || manualDiff.becameInactive()))) {
return RULE_TYPE_MANUAL;
}
}
@@ -391,10 +393,8 @@
if (config == null) {
return rules;
}
-
- if (config.manualRule != null) {
- // If the manual rule is non-null, then it's active. We make a copy and set the rule
- // type so that the correct value gets logged.
+ if (config.isManualActive()) {
+ // We make a copy and set the rule type so that the correct value gets logged.
ZenRule rule = config.manualRule.copy();
rule.type = ACTIVE_RULE_TYPE_MANUAL;
rules.add(rule);
@@ -592,10 +592,10 @@
// This applies to both call and message senders, but not conversation senders,
// where they use the same enum values.
proto.write(DNDPolicyProto.ALLOW_CALLS_FROM,
- ZenAdapters.notificationPolicySendersToZenPolicyPeopleType(
+ ZenAdapters.prioritySendersToPeopleType(
mNewPolicy.allowCallsFrom()));
proto.write(DNDPolicyProto.ALLOW_MESSAGES_FROM,
- ZenAdapters.notificationPolicySendersToZenPolicyPeopleType(
+ ZenAdapters.prioritySendersToPeopleType(
mNewPolicy.allowMessagesFrom()));
proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM,
mNewPolicy.allowConversationsFrom());
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 454bd20..267291c 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -24,6 +24,10 @@
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_UNKNOWN;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
+import static android.service.notification.Condition.SOURCE_UNKNOWN;
+import static android.service.notification.Condition.SOURCE_USER_ACTION;
+import static android.service.notification.Condition.STATE_FALSE;
+import static android.service.notification.Condition.STATE_TRUE;
import static android.service.notification.NotificationServiceProto.ROOT_CONFIG;
import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_APP;
import static android.service.notification.ZenModeConfig.UPDATE_ORIGIN_INIT;
@@ -216,7 +220,9 @@
mAppOps = context.getSystemService(AppOpsManager.class);
mNotificationManager = context.getSystemService(NotificationManager.class);
- mDefaultConfig = readDefaultConfig(mContext.getResources());
+ mDefaultConfig = Flags.modesUi()
+ ? ZenModeConfig.getDefaultConfig()
+ : readDefaultConfig(mContext.getResources());
updateDefaultConfigAutomaticRules();
if (Flags.modesApi()) {
updateDefaultAutomaticRulePolicies();
@@ -612,7 +618,7 @@
if (rule != null) {
Condition deactivated = new Condition(rule.conditionId,
mContext.getString(R.string.zen_mode_implicit_deactivated),
- Condition.STATE_FALSE);
+ STATE_FALSE);
setAutomaticZenRuleStateLocked(newConfig, Collections.singletonList(rule),
deactivated, UPDATE_ORIGIN_APP, callingUid);
}
@@ -627,8 +633,7 @@
// would apply if changing the global interruption filter. We only do this
// for newly created rules, as existing rules have a pre-existing policy
// (whether initialized here or set via app or user).
- rule.zenPolicy = mConfig.toZenPolicy();
-
+ rule.zenPolicy = mConfig.getZenPolicy().copy();
newConfig.automaticRules.put(rule.id, rule);
}
// If the user has changed the rule's *zenMode*, then don't let app overwrite it.
@@ -639,7 +644,7 @@
rule.snoozing = false;
rule.condition = new Condition(rule.conditionId,
mContext.getString(R.string.zen_mode_implicit_activated),
- Condition.STATE_TRUE);
+ STATE_TRUE);
setConfigLocked(newConfig, /* triggeringComponent= */ null, UPDATE_ORIGIN_APP,
"applyGlobalZenModeAsImplicitZenRule", callingUid);
@@ -687,7 +692,7 @@
// would take effect if changing the global policy.
// Note that NotificationManager.Policy cannot have any unset priority
// categories, but *can* have unset visual effects, which is why we do this.
- newZenPolicy = mConfig.toZenPolicy().overwrittenWith(newZenPolicy);
+ newZenPolicy = mConfig.getZenPolicy().overwrittenWith(newZenPolicy);
}
updatePolicy(
rule,
@@ -878,7 +883,7 @@
if (rule == null || !canManageAutomaticZenRule(rule)) {
return Condition.STATE_UNKNOWN;
}
- return rule.condition != null ? rule.condition.state : Condition.STATE_FALSE;
+ return rule.condition != null ? rule.condition.state : STATE_FALSE;
}
}
@@ -929,7 +934,7 @@
Condition condition, @ConfigChangeOrigin int origin, int callingUid) {
if (rules == null || rules.isEmpty()) return;
- if (Flags.modesApi() && condition.source == Condition.SOURCE_USER_ACTION) {
+ if (Flags.modesApi() && condition.source == SOURCE_USER_ACTION) {
origin = UPDATE_ORIGIN_USER; // Although coming from app, it's actually a user action.
}
@@ -1285,7 +1290,7 @@
if (isNew) {
// Newly created rule with no provided policy; fill in with the default.
zenRule.zenPolicy =
- Flags.modesUi() ? mDefaultConfig.toZenPolicy() : mConfig.toZenPolicy();
+ Flags.modesUi() ? mDefaultConfig.getZenPolicy() : mConfig.getZenPolicy();
return true;
}
// Otherwise, a null policy means no policy changes, so we can stop here.
@@ -1296,7 +1301,7 @@
// fields in the bitmask should be marked as updated.
ZenPolicy oldPolicy = zenRule.zenPolicy != null
? zenRule.zenPolicy
- : (Flags.modesUi() ? mDefaultConfig.toZenPolicy() : mConfig.toZenPolicy());
+ : (Flags.modesUi() ? mDefaultConfig.getZenPolicy() : mConfig.getZenPolicy());
// If this is updating a rule rather than creating a new one, keep any fields from the
// old policy if they are unspecified in the new policy. For newly created rules, oldPolicy
@@ -1524,9 +1529,15 @@
+ " conditionId=" + conditionId + " reason=" + reason
+ " setRingerMode=" + setRingerMode);
newConfig = mConfig.copy();
- if (zenMode == Global.ZEN_MODE_OFF) {
- newConfig.manualRule = null;
- if (!Flags.modesUi() || origin != UPDATE_ORIGIN_USER) {
+ if (Flags.modesUi()) {
+ newConfig.manualRule.enabler = caller;
+ newConfig.manualRule.conditionId = conditionId != null ? conditionId : Uri.EMPTY;
+ newConfig.manualRule.pkg = PACKAGE_ANDROID;
+ newConfig.manualRule.zenMode = zenMode;
+ newConfig.manualRule.condition = new Condition(newConfig.manualRule.conditionId, "",
+ zenMode == Global.ZEN_MODE_OFF ? STATE_FALSE : STATE_TRUE,
+ origin == UPDATE_ORIGIN_USER ? SOURCE_USER_ACTION : SOURCE_UNKNOWN);
+ if (zenMode == Global.ZEN_MODE_OFF && origin != UPDATE_ORIGIN_USER) {
// User deactivation of DND means just turning off the manual DND rule.
// For API calls (different origin) keep old behavior of snoozing all rules.
for (ZenRule automaticRule : newConfig.automaticRules.values()) {
@@ -1536,20 +1547,51 @@
}
}
} else {
- final ZenRule newRule = new ZenRule();
- newRule.enabled = true;
- newRule.zenMode = zenMode;
- newRule.conditionId = conditionId;
- newRule.enabler = caller;
- if (Flags.modesApi()) {
- newRule.allowManualInvocation = true;
+ if (zenMode == Global.ZEN_MODE_OFF) {
+ newConfig.manualRule = null;
+ // User deactivation of DND means just turning off the manual DND rule.
+ // For API calls (different origin) keep old behavior of snoozing all rules.
+ for (ZenRule automaticRule : newConfig.automaticRules.values()) {
+ if (automaticRule.isAutomaticActive()) {
+ automaticRule.snoozing = true;
+ }
+ }
+
+ } else {
+ final ZenRule newRule = new ZenRule();
+ newRule.enabled = true;
+ newRule.zenMode = zenMode;
+ newRule.conditionId = conditionId;
+ newRule.enabler = caller;
+ if (Flags.modesApi()) {
+ newRule.allowManualInvocation = true;
+ }
+ newConfig.manualRule = newRule;
}
- newConfig.manualRule = newRule;
}
setConfigLocked(newConfig, origin, reason, null, setRingerMode, callingUid);
}
}
+ public void setManualZenRuleDeviceEffects(ZenDeviceEffects deviceEffects,
+ @ConfigChangeOrigin int origin, String reason, int callingUid) {
+ if (!Flags.modesUi()) {
+ return;
+ }
+ ZenModeConfig newConfig;
+ synchronized (mConfigLock) {
+ if (mConfig == null) return;
+ if (DEBUG) Log.d(TAG, "updateManualRule " + deviceEffects
+ + " reason=" + reason
+ + " callingUid=" + callingUid);
+ newConfig = mConfig.copy();
+
+ newConfig.manualRule.pkg = PACKAGE_ANDROID;
+ newConfig.manualRule.zenDeviceEffects = deviceEffects;
+ setConfigLocked(newConfig, origin, reason, null, true, callingUid);
+ }
+ }
+
void dump(ProtoOutputStream proto) {
proto.write(ZenModeProto.ZEN_MODE, mZenMode);
synchronized (mConfigLock) {
@@ -1558,7 +1600,7 @@
}
for (ZenRule rule : mConfig.automaticRules.values()) {
if (rule.enabled && rule.condition != null
- && rule.condition.state == Condition.STATE_TRUE
+ && rule.condition.state == STATE_TRUE
&& !rule.snoozing) {
rule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
}
@@ -1592,33 +1634,7 @@
private static void dump(PrintWriter pw, String prefix, String var, ZenModeConfig config) {
pw.print(prefix); pw.print(var); pw.print('=');
- if (config == null) {
- pw.println(config);
- return;
- }
- pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,"
- + "messages=%b,messagesFrom=%s,conversations=%b,conversationsFrom=%s,"
- + "events=%b,reminders=%b",
- config.allowAlarms, config.allowMedia, config.allowSystem,
- config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
- config.allowRepeatCallers, config.allowMessages,
- ZenModeConfig.sourceToString(config.allowMessagesFrom),
- config.allowConversations,
- ZenPolicy.conversationTypeToString(config.allowConversationsFrom),
- config.allowEvents, config.allowReminders);
- if (Flags.modesApi()) {
- pw.printf(",priorityChannels=%b", config.allowPriorityChannels);
- }
- pw.printf(")\n");
- pw.print(prefix);
- pw.printf(" disallow(visualEffects=%s)\n", config.suppressedVisualEffects);
- pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule);
- if (config.automaticRules.isEmpty()) return;
- final int N = config.automaticRules.size();
- for (int i = 0; i < N; i++) {
- pw.print(prefix); pw.print(i == 0 ? " automaticRules=" : " ");
- pw.println(config.automaticRules.valueAt(i));
- }
+ pw.println(config);
}
public void readXml(TypedXmlPullParser parser, boolean forRestore, int userId)
@@ -1629,7 +1645,9 @@
if (config != null) {
if (forRestore) {
config.user = userId;
- config.manualRule = null; // don't restore the manual rule
+ if (!Flags.modesUi()) {
+ config.manualRule = null; // don't restore the manual rule
+ }
}
// booleans to determine whether to reset the rules to the default rules
@@ -1653,7 +1671,7 @@
// rules with null ZenPolicies explicitly as a copy of the global policy.
if (Flags.modesApi() && config.version < ZenModeConfig.XML_VERSION_MODES_API) {
// Keep the manual ("global") policy that from config.
- ZenPolicy manualRulePolicy = config.toZenPolicy();
+ ZenPolicy manualRulePolicy = config.getZenPolicy();
if (automaticRule.zenPolicy == null) {
automaticRule.zenPolicy = manualRulePolicy;
} else {
@@ -1842,7 +1860,7 @@
*/
@VisibleForTesting
protected ZenPolicy getDefaultZenPolicy() {
- return mDefaultConfig.toZenPolicy();
+ return mDefaultConfig.getZenPolicy();
}
@GuardedBy("mConfigLock")
@@ -2008,7 +2026,7 @@
private int computeZenMode() {
synchronized (mConfigLock) {
if (mConfig == null) return Global.ZEN_MODE_OFF;
- if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
+ if (mConfig.isManualActive()) return mConfig.manualRule.zenMode;
int zen = Global.ZEN_MODE_OFF;
for (ZenRule automaticRule : mConfig.automaticRules.values()) {
if (automaticRule.isAutomaticActive()) {
@@ -2047,19 +2065,19 @@
if (Flags.modesApi()) {
if (useManualConfig) {
// manual rule is configured using the settings stored directly in mConfig
- policy.apply(mConfig.toZenPolicy());
+ policy.apply(mConfig.getZenPolicy());
} else {
// under modes_api flag, an active automatic rule with no specified policy
// inherits the device default settings as stored in mDefaultConfig. While the
// rule's policy fields should be set upon creation, this is a fallback to
// catch any that may have fallen through the cracks.
Log.wtf(TAG, "active automatic rule found with no specified policy: " + rule);
- policy.apply(
- Flags.modesUi() ? mDefaultConfig.toZenPolicy() : mConfig.toZenPolicy());
+ policy.apply(Flags.modesUi()
+ ? mDefaultConfig.getZenPolicy() : mConfig.getZenPolicy());
}
} else {
- // active rule with no specified policy inherits the global config settings
- policy.apply(mConfig.toZenPolicy());
+ // active rule with no specified policy inherits the manual rule config settings
+ policy.apply(mConfig.getZenPolicy());
}
}
}
@@ -2071,7 +2089,7 @@
if (mConfig == null) return;
ZenPolicy policy = new ZenPolicy();
ZenDeviceEffects.Builder deviceEffectsBuilder = new ZenDeviceEffects.Builder();
- if (mConfig.manualRule != null) {
+ if (mConfig.isManualActive()) {
applyCustomPolicy(policy, mConfig.manualRule, true);
if (Flags.modesApi()) {
deviceEffectsBuilder.add(mConfig.manualRule.zenDeviceEffects);
@@ -2154,7 +2172,7 @@
// Should be checked before calling, but just in case.
return;
}
- ZenPolicy defaultPolicy = mDefaultConfig.toZenPolicy();
+ ZenPolicy defaultPolicy = mDefaultConfig.getZenPolicy();
for (ZenRule rule : mDefaultConfig.automaticRules.values()) {
if (ZenModeConfig.DEFAULT_RULE_IDS.contains(rule.id) && rule.zenPolicy == null) {
rule.zenPolicy = defaultPolicy.copy();
@@ -2335,17 +2353,17 @@
final ZenModeConfig config = mConfigs.valueAt(i);
events.add(FrameworkStatsLog.buildStatsEvent(DND_MODE_RULE,
/* optional int32 user = 1 */ user,
- /* optional bool enabled = 2 */ config.manualRule != null,
+ /* optional bool enabled = 2 */ config.isManualActive(),
/* optional bool channels_bypassing = 3 */ config.areChannelsBypassingDnd,
/* optional LoggedZenMode zen_mode = 4 */ ROOT_CONFIG,
/* optional string id = 5 */ "", // empty for root config
/* optional int32 uid = 6 */ Process.SYSTEM_UID, // system owns root config
- /* optional DNDPolicyProto policy = 7 */ config.toZenPolicy().toProto(),
+ /* optional DNDPolicyProto policy = 7 */ config.getZenPolicy().toProto(),
/* optional int32 rule_modified_fields = 8 */ 0,
/* optional int32 policy_modified_fields = 9 */ 0,
/* optional int32 device_effects_modified_fields = 10 */ 0,
/* optional ActiveRuleType rule_type = 11 */ TYPE_UNKNOWN));
- if (config.manualRule != null) {
+ if (config.isManualActive()) {
ruleToProtoLocked(user, config.manualRule, true, events);
}
for (ZenRule rule : config.automaticRules.values()) {
diff --git a/services/core/java/com/android/server/pm/KillAppBlocker.java b/services/core/java/com/android/server/pm/KillAppBlocker.java
index e2901c3..7f5ad9d 100644
--- a/services/core/java/com/android/server/pm/KillAppBlocker.java
+++ b/services/core/java/com/android/server/pm/KillAppBlocker.java
@@ -83,13 +83,13 @@
}
}
- void waitAppProcessGone(ActivityManagerInternal mAmi, Computer snapshot,
+ void waitAppProcessGone(ActivityManagerInternal ami, Computer snapshot,
UserManagerService userManager, String packageName) {
if (!mRegistered) {
return;
}
synchronized (this) {
- if (mAmi != null) {
+ if (ami != null) {
int[] users = userManager.getUserIds();
for (int i = 0; i < users.length; i++) {
@@ -97,12 +97,16 @@
final int uid = snapshot.getPackageUidInternal(
packageName, MATCH_ALL, userId, Process.SYSTEM_UID);
if (uid != INVALID_UID) {
- if (mAmi.getUidProcessState(uid) != PROCESS_STATE_NONEXISTENT) {
+ if (ami.getUidProcessState(uid) != PROCESS_STATE_NONEXISTENT) {
mActiveUids.add(uid);
}
}
}
}
+ if (mActiveUids.size() == 0) {
+ // no active uid
+ return;
+ }
}
try {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 80c262a..11b9e77 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -17,7 +17,6 @@
package com.android.server.power;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
@@ -198,10 +197,9 @@
FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
Executor backgroundExecutor, PowerManagerFlags powerManagerFlags, Injector injector) {
mContext = context;
- mInjector = (injector == null) ? new RealInjector() : injector;
mFlags = powerManagerFlags;
mBatteryStats = batteryStats;
- mAppOps = mInjector.getAppOpsManager(context);
+ mAppOps = mContext.getSystemService(AppOpsManager.class);
mSuspendBlocker = suspendBlocker;
mPolicy = policy;
mFaceDownDetector = faceDownDetector;
@@ -232,6 +230,7 @@
mShowWirelessChargingAnimationConfig = context.getResources().getBoolean(
com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim);
+ mInjector = (injector == null) ? new RealInjector() : injector;
mWakeLockLog = mInjector.getWakeLockLog(context);
// Initialize interactive state for battery stats.
try {
@@ -265,7 +264,6 @@
/**
* Called when a wake lock is acquired.
*/
- @SuppressLint("AndroidFrameworkRequiresPermission")
public void onWakeLockAcquired(int flags, String tag, String packageName,
int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
IWakeLockCallback callback) {
@@ -275,28 +273,27 @@
+ ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+ ", workSource=" + workSource);
}
- notifyWakeLockListener(callback, tag, true, ownerUid, ownerPid, flags, workSource,
- packageName, historyTag);
- if (!mFlags.improveWakelockLatency()) {
- final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
- if (monitorType >= 0) {
- try {
- final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID
- && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
- if (workSource != null) {
- mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag,
- historyTag, monitorType, unimportantForLogging);
- } else {
- mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
- monitorType, unimportantForLogging);
- // XXX need to deal with disabled operations.
- mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName,
- false, null, null);
- }
- } catch (RemoteException ex) {
- // Ignore
+ notifyWakeLockListener(callback, tag, true, ownerUid, flags);
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (monitorType >= 0) {
+ try {
+ final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID
+ && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
+ if (workSource != null) {
+ mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag,
+ historyTag, monitorType, unimportantForLogging);
+ } else {
+ mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
+ monitorType, unimportantForLogging);
+ // XXX need to deal with disabled operations.
+ mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
}
+ } catch (RemoteException ex) {
+ // Ignore
}
+ }
+
+ if (!mFlags.improveWakelockLatency()) {
mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, /*eventTime=*/ -1);
}
mWakefulnessSessionObserver.onWakeLockAcquired(flags);
@@ -407,7 +404,6 @@
/**
* Called when a wake lock is released.
*/
- @SuppressLint("AndroidFrameworkRequiresPermission")
public void onWakeLockReleased(int flags, String tag, String packageName,
int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
IWakeLockCallback callback, int releaseReason) {
@@ -417,24 +413,23 @@
+ ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+ ", workSource=" + workSource);
}
- notifyWakeLockListener(callback, tag, false, ownerUid, ownerPid, flags, workSource,
- packageName, historyTag);
- if (!mFlags.improveWakelockLatency()) {
- final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
- if (monitorType >= 0) {
- try {
- if (workSource != null) {
- mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag,
- historyTag, monitorType);
- } else {
- mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
- historyTag, monitorType);
- mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName, null);
- }
- } catch (RemoteException ex) {
- // Ignore
+ notifyWakeLockListener(callback, tag, false, ownerUid, flags);
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (monitorType >= 0) {
+ try {
+ if (workSource != null) {
+ mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag,
+ historyTag, monitorType);
+ } else {
+ mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
+ historyTag, monitorType);
+ mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
}
+ } catch (RemoteException ex) {
+ // Ignore
}
+ }
+ if (!mFlags.improveWakelockLatency()) {
mWakeLockLog.onWakeLockReleased(tag, ownerUid, /*eventTime=*/ -1);
}
mWakefulnessSessionObserver.onWakeLockReleased(flags, releaseReason);
@@ -1054,75 +1049,24 @@
}
private void notifyWakeLockListener(IWakeLockCallback callback, String tag, boolean isEnabled,
- int ownerUid, int ownerPid, int flags, WorkSource workSource, String packageName,
- String historyTag) {
- if (mFlags.improveWakelockLatency()) {
- if (callback != null) {
- long currentTime = mInjector.currentTimeMillis();
- mHandler.post(() -> {
- try {
+ int ownerUid, int flags) {
+ if (callback != null) {
+ long currentTime = mInjector.currentTimeMillis();
+ mHandler.post(() -> {
+ try {
+ if (mFlags.improveWakelockLatency()) {
if (isEnabled) {
- notifyWakelockAcquisition(tag, ownerUid, ownerPid, flags,
- workSource, packageName, historyTag, currentTime);
+ mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, currentTime);
} else {
- notifyWakelockRelease(tag, ownerUid, ownerPid, flags,
- workSource, packageName, historyTag, currentTime);
+ mWakeLockLog.onWakeLockReleased(tag, ownerUid, currentTime);
}
- callback.onStateChanged(isEnabled);
- } catch (RemoteException e) {
- Slog.e(TAG, "Wakelock.mCallback [" + tag + "] is already dead.", e);
}
- });
- }
- }
-
- }
-
- @SuppressLint("AndroidFrameworkRequiresPermission")
- private void notifyWakelockAcquisition(String tag, int ownerUid, int ownerPid, int flags,
- WorkSource workSource, String packageName, String historyTag, long currentTime) {
- final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
- if (monitorType >= 0) {
- try {
- final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID
- && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
- if (workSource != null) {
- mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag,
- historyTag, monitorType, unimportantForLogging);
- } else {
- mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
- monitorType, unimportantForLogging);
- // XXX need to deal with disabled operations.
- mAppOps.startOpNoThrow(
- AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName,
- false, null, null);
+ callback.onStateChanged(isEnabled);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Wakelock.mCallback [" + tag + "] is already dead.", e);
}
- } catch (RemoteException ex) {
- // Do Nothing
- }
+ });
}
- mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, currentTime);
- }
-
- @SuppressLint("AndroidFrameworkRequiresPermission")
- private void notifyWakelockRelease(String tag, int ownerUid, int ownerPid, int flags,
- WorkSource workSource, String packageName, String historyTag, long currentTime) {
- final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
- if (monitorType >= 0) {
- try {
- if (workSource != null) {
- mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag,
- historyTag, monitorType);
- } else {
- mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
- historyTag, monitorType);
- mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName, null);
- }
- } catch (RemoteException ex) {
- // Ignore
- }
- }
- mWakeLockLog.onWakeLockReleased(tag, ownerUid, currentTime);
}
private final class NotifierHandler extends Handler {
@@ -1170,11 +1114,6 @@
* Gets the WakeLockLog object
*/
WakeLockLog getWakeLockLog(Context context);
-
- /**
- * Gets the AppOpsManager system service
- */
- AppOpsManager getAppOpsManager(Context context);
}
static class RealInjector implements Injector {
@@ -1187,10 +1126,5 @@
public WakeLockLog getWakeLockLog(Context context) {
return new WakeLockLog(context);
}
-
- @Override
- public AppOpsManager getAppOpsManager(Context context) {
- return context.getSystemService(AppOpsManager.class);
- }
}
}
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index df502eb..06595ac 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -19,6 +19,7 @@
import static android.os.Flags.adpfUseFmqChannel;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+import static com.android.server.power.hint.Flags.adpfSessionTag;
import static com.android.server.power.hint.Flags.powerhintThreadCleanup;
import android.annotation.NonNull;
@@ -28,6 +29,8 @@
import android.app.StatsManager;
import android.app.UidObserver;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.hardware.power.ChannelConfig;
import android.hardware.power.IPower;
import android.hardware.power.SessionConfig;
@@ -130,6 +133,7 @@
private final IPower mPowerHal;
private int mPowerHalVersion;
+ private final PackageManager mPackageManager;
private static final String PROPERTY_SF_ENABLE_CPU_HINT = "debug.sf.enable_adpf_cpu_hint";
private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager";
@@ -151,6 +155,11 @@
mCleanUpHandler = null;
mNonIsolatedTids = null;
}
+ if (adpfSessionTag()) {
+ mPackageManager = mContext.getPackageManager();
+ } else {
+ mPackageManager = null;
+ }
mActiveSessions = new ArrayMap<>();
mChannelMap = new ArrayMap<>();
mNativeWrapper = injector.createNativeWrapper();
@@ -819,6 +828,25 @@
throw new SecurityException(errMsg);
}
+ if (adpfSessionTag() && tag == SessionTag.APP) {
+ // If the category of the app is a game,
+ // we change the session tag to SessionTag.GAME
+ // as it was not previously classified
+ switch (getUidApplicationCategory(callingUid)) {
+ case ApplicationInfo.CATEGORY_GAME:
+ tag = SessionTag.GAME;
+ break;
+ case ApplicationInfo.CATEGORY_UNDEFINED:
+ // We use CATEGORY_UNDEFINED to filter the case when
+ // PackageManager.NameNotFoundException is caught,
+ // which should not happen.
+ tag = SessionTag.APP;
+ break;
+ default:
+ tag = SessionTag.APP;
+ }
+ }
+
Long halSessionPtr = null;
if (mConfigCreationSupport.get()) {
try {
@@ -857,7 +885,10 @@
}
}
- logPerformanceHintSessionAtom(callingUid, halSessionPtr, durationNanos, tids);
+ final long sessionId = config != null ? config.id : halSessionPtr;
+ logPerformanceHintSessionAtom(
+ callingUid, sessionId, durationNanos, tids, tag);
+
synchronized (mLock) {
AppHintSession hs = new AppHintSession(callingUid, callingTgid, tids, token,
halSessionPtr, durationNanos);
@@ -944,9 +975,20 @@
}
private void logPerformanceHintSessionAtom(int uid, long sessionId,
- long targetDuration, int[] tids) {
+ long targetDuration, int[] tids, @SessionTag int sessionTag) {
FrameworkStatsLog.write(FrameworkStatsLog.PERFORMANCE_HINT_SESSION_REPORTED, uid,
- sessionId, targetDuration, tids.length);
+ sessionId, targetDuration, tids.length, sessionTag);
+ }
+
+ private int getUidApplicationCategory(int uid) {
+ try {
+ final String packageName = mPackageManager.getNameForUid(uid);
+ final ApplicationInfo applicationInfo =
+ mPackageManager.getApplicationInfo(packageName, PackageManager.MATCH_ALL);
+ return applicationInfo.category;
+ } catch (PackageManager.NameNotFoundException e) {
+ return ApplicationInfo.CATEGORY_UNDEFINED;
+ }
}
}
diff --git a/services/core/java/com/android/server/power/hint/TEST_MAPPING b/services/core/java/com/android/server/power/hint/TEST_MAPPING
index ce6277d..34c25c6 100644
--- a/services/core/java/com/android/server/power/hint/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/hint/TEST_MAPPING
@@ -10,16 +10,18 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
- },
+ }
+ ],
+ "postsubmit": [
{
"name": "CtsStatsdAtomHostTestCases",
"options": [
{"exclude-annotation": "androidx.test.filters.FlakyTest"},
{"exclude-annotation": "org.junit.Ignore"},
- {"include-filter": "android.cts.statsdatom.powermanager"}
+ {"include-filter": "android.cts.statsdatom.performancehintmanager"}
],
"file_patterns": [
- "(/|^)ThermalManagerService.java"
+ "(/|^)HintManagerService.java"
]
}
]
diff --git a/services/core/java/com/android/server/power/hint/flags.aconfig b/services/core/java/com/android/server/power/hint/flags.aconfig
index 0997744..55afa05 100644
--- a/services/core/java/com/android/server/power/hint/flags.aconfig
+++ b/services/core/java/com/android/server/power/hint/flags.aconfig
@@ -7,3 +7,10 @@
description: "Feature flag for auto PowerHintSession dead thread cleanup"
bug: "296160319"
}
+
+flag {
+ name: "adpf_session_tag"
+ namespace: "game"
+ description: "Feature flag for adding session tag to hint session atom"
+ bug: "345011125"
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 15f4c8c..edc5696 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -8699,7 +8699,11 @@
rotation = mDisplayContent.getRotation();
}
if (!mOptOutEdgeToEdge && (!mResolveConfigHint.mUseOverrideInsetsForConfig
- || getCompatDisplayInsets() != null || isFloating(parentWindowingMode)
+ || getCompatDisplayInsets() != null
+ || (isFloating(parentWindowingMode)
+ // Check the windowing mode of activity as well in case it is switching
+ // between PiP and fullscreen.
+ && isFloating(inOutConfig.windowConfiguration.getWindowingMode()))
|| rotation == ROTATION_UNDEFINED)) {
// If the insets configuration decoupled logic is not enabled for the app, or the app
// already has a compat override, or the context doesn't contain enough info to
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp
index 957d7c3..ce05c82 100644
--- a/services/incremental/Android.bp
+++ b/services/incremental/Android.bp
@@ -66,7 +66,6 @@
"libprotobuf-cpp-lite",
"service.incremental.proto",
"libvold_binder",
- "libc++fs",
"libziparchive_for_incfs",
],
shared_libs: [
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cfe4e17..107c294 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1196,11 +1196,12 @@
mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);
t.traceEnd();
+ // Initialize RescueParty.
+ RescueParty.registerHealthObserver(mSystemContext);
if (!Flags.recoverabilityDetection()) {
// Now that we have the bare essentials of the OS up and running, take
// note that we just booted, which might send out a rescue party if
// we're stuck in a runtime restart loop.
- RescueParty.registerHealthObserver(mSystemContext);
PackageWatchdog.getInstance(mSystemContext).noteBoot();
}
@@ -2917,10 +2918,10 @@
t.traceEnd();
if (Flags.recoverabilityDetection()) {
- // Now that we have the essential services needed for rescue party, initialize
- // RescuParty. note that we just booted, which might send out a rescue party if
- // we're stuck in a runtime restart loop.
- RescueParty.registerHealthObserver(mSystemContext);
+ // Now that we have the essential services needed for mitigations, register the boot
+ // with package watchdog.
+ // Note that we just booted, which might send out a rescue party if we're stuck in a
+ // runtime restart loop.
PackageWatchdog.getInstance(mSystemContext).noteBoot();
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 28c7fb2..488ce66 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -44,6 +44,7 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.android.server.am.ActivityManagerService.FOLLOW_UP_OOMADJUSTER_UPDATE_MSG;
import static com.android.server.am.ProcessList.BACKUP_APP_ADJ;
import static com.android.server.am.ProcessList.CACHED_APP_MAX_ADJ;
import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
@@ -77,6 +78,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doNothing;
@@ -113,11 +115,10 @@
import com.android.server.wm.WindowProcessController;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import java.io.File;
import java.lang.reflect.Field;
@@ -164,92 +165,86 @@
private static int sFirstCachedAdj = ProcessList.CACHED_APP_MIN_ADJ
+ ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
- private static Context sContext;
- private static PackageManagerInternal sPackageManagerInternal;
- private static ActivityManagerService sService;
+ private Context mContext;
+ private PackageManagerInternal mPackageManagerInternal;
+ private ActivityManagerService mService;
+ private OomAdjusterInjector mInjector = new OomAdjusterInjector();
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@SuppressWarnings("GuardedBy")
- @BeforeClass
- public static void setUpOnce() {
- sContext = getInstrumentation().getTargetContext();
+ @Before
+ public void setUp() {
+ mContext = getInstrumentation().getTargetContext();
System.setProperty("dexmaker.share_classloader", "true");
- sPackageManagerInternal = mock(PackageManagerInternal.class);
- doReturn(new ComponentName("", "")).when(sPackageManagerInternal)
+ mPackageManagerInternal = mock(PackageManagerInternal.class);
+ doReturn(new ComponentName("", "")).when(mPackageManagerInternal)
.getSystemUiServiceComponent();
// Remove stale instance of PackageManagerInternal if there is any
LocalServices.removeServiceForTest(PackageManagerInternal.class);
- LocalServices.addService(PackageManagerInternal.class, sPackageManagerInternal);
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
- sService = mock(ActivityManagerService.class);
- sService.mActivityTaskManager = new ActivityTaskManagerService(sContext);
- sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper());
- sService.mPackageManagerInt = sPackageManagerInternal;
- sService.mAtmInternal = spy(sService.mActivityTaskManager.getAtmInternal());
+ mService = mock(ActivityManagerService.class);
+ mService.mActivityTaskManager = new ActivityTaskManagerService(mContext);
+ mService.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
+ mService.mPackageManagerInt = mPackageManagerInternal;
+ mService.mAtmInternal = spy(mService.mActivityTaskManager.getAtmInternal());
- sService.mConstants = new ActivityManagerConstants(sContext, sService,
- sContext.getMainThreadHandler());
- setFieldValue(ActivityManagerService.class, sService, "mContext",
- sContext);
+ mService.mConstants = new ActivityManagerConstants(mContext, mService,
+ mContext.getMainThreadHandler());
+ setFieldValue(ActivityManagerService.class, mService, "mContext",
+ mContext);
ProcessList pr = spy(new ProcessList());
- pr.mService = sService;
+ pr.mService = mService;
AppProfiler profiler = mock(AppProfiler.class);
- setFieldValue(ActivityManagerService.class, sService, "mProcessList",
+ setFieldValue(ActivityManagerService.class, mService, "mProcessList",
pr);
- setFieldValue(ActivityManagerService.class, sService, "mHandler",
+ setFieldValue(ActivityManagerService.class, mService, "mHandler",
mock(ActivityManagerService.MainHandler.class));
- setFieldValue(ActivityManagerService.class, sService, "mProcessStats",
- new ProcessStatsService(sService, new File(sContext.getFilesDir(), "procstats")));
- setFieldValue(ActivityManagerService.class, sService, "mBackupTargets",
+ setFieldValue(ActivityManagerService.class, mService, "mProcessStats",
+ new ProcessStatsService(mService, new File(mContext.getFilesDir(), "procstats")));
+ setFieldValue(ActivityManagerService.class, mService, "mBackupTargets",
mock(SparseArray.class));
- setFieldValue(ActivityManagerService.class, sService, "mUserController",
+ setFieldValue(ActivityManagerService.class, mService, "mUserController",
mock(UserController.class));
- setFieldValue(ActivityManagerService.class, sService, "mAppProfiler", profiler);
- setFieldValue(ActivityManagerService.class, sService, "mProcLock",
+ setFieldValue(ActivityManagerService.class, mService, "mAppProfiler", profiler);
+ setFieldValue(ActivityManagerService.class, mService, "mProcLock",
new ActivityManagerProcLock());
- setFieldValue(ActivityManagerService.class, sService, "mServices",
- spy(new ActiveServices(sService)));
- setFieldValue(ActivityManagerService.class, sService, "mInternal",
+ setFieldValue(ActivityManagerService.class, mService, "mServices",
+ spy(new ActiveServices(mService)));
+ setFieldValue(ActivityManagerService.class, mService, "mInternal",
mock(ActivityManagerService.LocalService.class));
- setFieldValue(ActivityManagerService.class, sService, "mBatteryStatsService",
+ setFieldValue(ActivityManagerService.class, mService, "mBatteryStatsService",
mock(BatteryStatsService.class));
- setFieldValue(ActivityManagerService.class, sService, "mInjector",
- new ActivityManagerService.Injector(sContext));
- doReturn(mock(AppOpsManager.class)).when(sService).getAppOpsManager();
- doCallRealMethod().when(sService).enqueueOomAdjTargetLocked(any(ProcessRecord.class));
- doCallRealMethod().when(sService).updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_ACTIVITY);
+ setFieldValue(ActivityManagerService.class, mService, "mInjector",
+ new ActivityManagerService.Injector(mContext));
+ doReturn(mock(AppOpsManager.class)).when(mService).getAppOpsManager();
+ doCallRealMethod().when(mService).enqueueOomAdjTargetLocked(any(ProcessRecord.class));
+ doCallRealMethod().when(mService).updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_ACTIVITY);
setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
doReturn(new ActivityManagerService.ProcessChangeItem()).when(pr)
.enqueueProcessChangeItemLocked(anyInt(), anyInt());
- sService.mOomAdjuster = sService.mConstants.ENABLE_NEW_OOMADJ
- ? new OomAdjusterModernImpl(sService, sService.mProcessList,
- new ActiveUids(sService, false))
- : new OomAdjuster(sService, sService.mProcessList, new ActiveUids(sService, false));
- sService.mOomAdjuster.mAdjSeq = 10000;
- sService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
- if (sService.mConstants.USE_TIERED_CACHED_ADJ) {
+ mService.mOomAdjuster = mService.mConstants.ENABLE_NEW_OOMADJ
+ ? new OomAdjusterModernImpl(mService, mService.mProcessList,
+ new ActiveUids(mService, false), mInjector)
+ : new OomAdjuster(mService, mService.mProcessList, new ActiveUids(mService, false),
+ mInjector);
+ mService.mOomAdjuster.mAdjSeq = 10000;
+ mService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ if (mService.mConstants.USE_TIERED_CACHED_ADJ) {
sFirstCachedAdj = ProcessList.CACHED_APP_MIN_ADJ + 10;
}
- }
-
- @Before
- public void setUp() {
mSetFlagsRule.enableFlags(Flags.FLAG_NEW_FGS_RESTRICTION_LOGIC);
}
- @AfterClass
- public static void tearDownOnce() {
- LocalServices.removeServiceForTest(PackageManagerInternal.class);
- }
-
@SuppressWarnings("GuardedBy")
@After
public void tearDown() {
- sService.mOomAdjuster.resetInternal();
- sService.mOomAdjuster.mActiveUids.clear();
+ mService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.mActiveUids.clear();
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
}
private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
@@ -278,7 +273,7 @@
*/
@SuppressWarnings("GuardedBy")
private void setProcessesToLru(ProcessRecord... apps) {
- ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
+ ArrayList<ProcessRecord> lru = mService.mProcessList.getLruProcessesLOSP();
lru.clear();
Collections.addAll(lru, apps);
}
@@ -292,20 +287,20 @@
@SuppressWarnings("GuardedBy")
private void updateOomAdj(ProcessRecord... apps) {
if (apps.length == 0) {
- updateProcessRecordNodes(sService.mProcessList.getLruProcessesLOSP());
- sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ updateProcessRecordNodes(mService.mProcessList.getLruProcessesLOSP());
+ mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
} else {
updateProcessRecordNodes(Arrays.asList(apps));
if (apps.length == 1) {
final ProcessRecord app = apps[0];
- if (!sService.mProcessList.getLruProcessesLOSP().contains(app)) {
- sService.mProcessList.getLruProcessesLOSP().add(app);
+ if (!mService.mProcessList.getLruProcessesLOSP().contains(app)) {
+ mService.mProcessList.getLruProcessesLOSP().add(app);
}
- sService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE);
+ mService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE);
} else {
setProcessesToLru(apps);
- sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
- sService.mProcessList.getLruProcessesLOSP().clear();
+ mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ mService.mProcessList.getLruProcessesLOSP().clear();
}
}
}
@@ -318,10 +313,10 @@
private void updateOomAdjPending(ProcessRecord... apps) {
setProcessesToLru(apps);
for (ProcessRecord app : apps) {
- sService.mOomAdjuster.enqueueOomAdjTargetLocked(app);
+ mService.mOomAdjuster.enqueueOomAdjTargetLocked(app);
}
- sService.mOomAdjuster.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_NONE);
- sService.mProcessList.getLruProcessesLOSP().clear();
+ mService.mOomAdjuster.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_NONE);
+ mService.mProcessList.getLruProcessesLOSP().clear();
}
/**
@@ -343,9 +338,9 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
app.mState.setHasTopUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
updateOomAdj(app);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERSISTENT_PROC_ADJ,
SCHED_GROUP_RESTRICTED);
@@ -359,7 +354,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
app.mState.setHasTopUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_PERSISTENT_UI, PERSISTENT_PROC_ADJ,
@@ -372,10 +367,10 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- doReturn(app).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(app).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_PERSISTENT_UI, PERSISTENT_PROC_ADJ,
SCHED_GROUP_TOP_APP);
@@ -386,11 +381,11 @@
public void testUpdateOomAdj_DoOne_TopApp_Awake() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(app).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(app).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_TOP, FOREGROUND_APP_ADJ, SCHED_GROUP_TOP_APP);
}
@@ -400,11 +395,11 @@
public void testUpdateOomAdj_DoOne_RunningAnimations() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(PROCESS_STATE_TOP_SLEEPING).when(sService.mAtmInternal).getTopProcessState();
+ doReturn(PROCESS_STATE_TOP_SLEEPING).when(mService.mAtmInternal).getTopProcessState();
app.mState.setRunningRemoteAnimation(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
assertProcStates(app, PROCESS_STATE_TOP_SLEEPING, VISIBLE_APP_ADJ, SCHED_GROUP_TOP_APP);
}
@@ -415,7 +410,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(mock(ActiveInstrumentation.class)).when(app).getActiveInstrumentation();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doCallRealMethod().when(app).getActiveInstrumentation();
@@ -429,11 +424,11 @@
public void testUpdateOomAdj_DoOne_ReceivingBroadcast() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(true).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
+ doReturn(true).when(mService).isReceivingBroadcastLocked(any(ProcessRecord.class),
any(int[].class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
- doReturn(false).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
+ doReturn(false).when(mService).isReceivingBroadcastLocked(any(ProcessRecord.class),
any(int[].class));
assertProcStates(app, PROCESS_STATE_RECEIVER, FOREGROUND_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -445,7 +440,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.startExecutingService(mock(ServiceRecord.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_SERVICE, FOREGROUND_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -456,13 +451,13 @@
public void testUpdateOomAdj_DoOne_TopApp_Sleeping() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(PROCESS_STATE_TOP_SLEEPING).when(sService.mAtmInternal).getTopProcessState();
- doReturn(app).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+ doReturn(PROCESS_STATE_TOP_SLEEPING).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(app).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
updateOomAdj(app);
- doReturn(null).when(sService).getTopApp();
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(null).when(mService).getTopApp();
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
assertProcStates(app, PROCESS_STATE_TOP_SLEEPING, FOREGROUND_APP_ADJ,
SCHED_GROUP_BACKGROUND);
@@ -475,8 +470,8 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setCurRawAdj(CACHED_APP_MIN_ADJ);
app.mState.setCurAdj(CACHED_APP_MIN_ADJ);
- doReturn(null).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(null).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
final int expectedAdj = sFirstCachedAdj;
@@ -505,7 +500,7 @@
return 0;
})).when(wpc).computeOomAdjFromActivities(
any(WindowProcessController.ComputeOomAdjCallback.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_TOP_APP);
@@ -522,7 +517,7 @@
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).hasRecentTasks();
app.mState.setLastTopTime(SystemClock.uptimeMillis());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doCallRealMethod().when(wpc).hasRecentTasks();
@@ -536,7 +531,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.setHasForegroundServices(true, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION,
/* hasNoneType=*/false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -550,7 +545,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -561,10 +556,10 @@
@SuppressWarnings("GuardedBy")
@Test
public void testUpdateOomAdj_DoOne_FgService_ShortFgs() {
- sService.mConstants.TOP_TO_FGS_GRACE_DURATION = 100_000;
- sService.mConstants.mShortFgsProcStateExtraWaitDuration = 200_000;
+ mService.mConstants.TOP_TO_FGS_GRACE_DURATION = 100_000;
+ mService.mConstants.mShortFgsProcStateExtraWaitDuration = 200_000;
- ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
@@ -579,7 +574,7 @@
app.mServices.setHasForegroundServices(true,
FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
app.mState.setLastTopTime(SystemClock.uptimeMillis());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -596,8 +591,8 @@
FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
app.mServices.startService(s);
app.mState.setLastTopTime(SystemClock.uptimeMillis()
- - sService.mConstants.TOP_TO_FGS_GRACE_DURATION);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ - mService.mConstants.TOP_TO_FGS_GRACE_DURATION);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -607,14 +602,14 @@
}
// SHORT_SERVICE, timed out already.
- s = ServiceRecord.newEmptyInstanceForTest(sService);
+ s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
s.setShortFgsInfo(SystemClock.uptimeMillis()
- - sService.mConstants.mShortFgsTimeoutDuration
- - sService.mConstants.mShortFgsProcStateExtraWaitDuration);
+ - mService.mConstants.mShortFgsTimeoutDuration
+ - mService.mConstants.mShortFgsProcStateExtraWaitDuration);
{
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
@@ -622,8 +617,8 @@
FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
app.mServices.startService(s);
app.mState.setLastTopTime(SystemClock.uptimeMillis()
- - sService.mConstants.TOP_TO_FGS_GRACE_DURATION);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ - mService.mConstants.TOP_TO_FGS_GRACE_DURATION);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -639,7 +634,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setHasOverlayUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
@@ -653,12 +648,26 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
app.mState.setLastTopTime(SystemClock.uptimeMillis());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE,
- PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT);
+ PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT, "fg-service-act");
assertBfsl(app);
+
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler).sendEmptyMessageAtTime(
+ eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ SCHED_GROUP_DEFAULT, "fg-service");
+ // Follow up should not have been called again.
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
}
@SuppressWarnings("GuardedBy")
@@ -678,12 +687,24 @@
s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler).sendEmptyMessageAtTime(
+ eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertEquals(sFirstCachedAdj, app.mState.getSetAdj());
+ // Follow up should not have been called again.
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
+
}
// Out of grace period but valid binding allows the adjustment.
@@ -698,14 +719,14 @@
ServiceRecord s = bindService(app, system,
null, null, Context.BIND_ALMOST_PERCEPTIBLE + 2, mock(IBinder.class));
s.lastTopAlmostPerceptibleBindRequestUptimeMs =
- nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
+ nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
// Out of grace period and no valid binding so no adjustment.
@@ -720,15 +741,15 @@
ServiceRecord s = bindService(app, system,
null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
s.lastTopAlmostPerceptibleBindRequestUptimeMs =
- nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
+ nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertNotEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
}
@@ -744,7 +765,7 @@
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(system, app);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND,
@@ -757,7 +778,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setForcingToImportant(new Object());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -771,7 +792,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isHeavyWeightProcess();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doReturn(false).when(wpc).isHeavyWeightProcess();
@@ -786,7 +807,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isHomeProcess();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_HOME, HOME_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -800,11 +821,25 @@
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isPreviousProcess();
doReturn(true).when(wpc).hasActivities();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
- SCHED_GROUP_BACKGROUND);
+ SCHED_GROUP_BACKGROUND, "previous");
+
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, CACHED_APP_MIN_ADJ,
+ SCHED_GROUP_BACKGROUND, "previous-expired");
+ // Follow up should not have been called again.
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
}
@SuppressWarnings("GuardedBy")
@@ -814,10 +849,10 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
backupTarget.app = app;
- doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
- doReturn(null).when(sService.mBackupTargets).get(anyInt());
+ doReturn(null).when(mService.mBackupTargets).get(anyInt());
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, BACKUP_APP_ADJ,
SCHED_GROUP_BACKGROUND);
@@ -829,7 +864,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.setHasClientActivities(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY_CLIENT, app.mState.getSetProcState());
@@ -841,7 +876,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.setTreatLikeActivity(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.mState.getSetProcState());
@@ -858,7 +893,7 @@
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
app.mServices.startService(s);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_B_ADJ, SCHED_GROUP_BACKGROUND);
@@ -870,7 +905,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.mState.setMaxAdj(PERCEPTIBLE_LOW_APP_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, PERCEPTIBLE_LOW_APP_ADJ,
@@ -884,8 +919,8 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.mState.setCurRawAdj(SERVICE_ADJ);
app.mState.setCurAdj(SERVICE_ADJ);
- doReturn(null).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(null).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertTrue(ProcessList.CACHED_APP_MIN_ADJ <= app.mState.getSetAdj());
@@ -902,7 +937,7 @@
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
app.mServices.startService(s);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -918,11 +953,11 @@
ServiceRecord s = bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY,
mock(IBinder.class));
s.startRequested = true;
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client).when(mService).getTopApp();
updateOomAdj(client, app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_SERVICE, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
}
@@ -937,7 +972,7 @@
client.mServices.setTreatLikeActivity(true);
bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY
| Context.BIND_TREAT_LIKE_ACTIVITY, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.mState.getSetProcState());
@@ -956,9 +991,9 @@
ConnectionRecord cr = s.getConnections().get(binder).get(0);
setFieldValue(ConnectionRecord.class, cr, "activity",
mock(ActivityServiceConnectionsHolder.class));
- doReturn(client).when(sService).getTopApp();
+ doReturn(client).when(mService).getTopApp();
doReturn(true).when(cr.activity).isActivityVisible();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -971,7 +1006,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
bindService(app, app, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
@@ -986,7 +1021,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
client.mServices.setTreatLikeActivity(true);
bindService(app, client, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_CACHED_EMPTY, app.mState.getSetProcState());
@@ -1005,11 +1040,11 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_ALLOW_OOM_MANAGEMENT,
mock(IBinder.class));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertEquals(PREVIOUS_APP_ADJ, app.mState.getSetAdj());
}
@@ -1024,7 +1059,7 @@
bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
client.mState.setHasTopUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -1041,7 +1076,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_IMPORTANT, mock(IBinder.class));
client.mServices.startExecutingService(mock(ServiceRecord.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -1056,11 +1091,11 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, 0, mock(IBinder.class));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_DEFAULT);
}
@@ -1074,7 +1109,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_BOUND_FOREGROUND_SERVICE, app.mState.getSetProcState());
@@ -1092,7 +1127,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app.mState.getSetProcState());
@@ -1108,7 +1143,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_FOREGROUND_SERVICE, client.mState.getSetProcState());
@@ -1128,7 +1163,7 @@
bindService(app, client, null, null, 0, mock(IBinder.class));
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
- ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
@@ -1139,7 +1174,7 @@
client.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
/* hasNoneType=*/false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
// Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1159,7 +1194,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
- ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
@@ -1170,7 +1205,7 @@
app2.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
/* hasNoneType=*/false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app2);
// Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1211,11 +1246,11 @@
bindService(app, client, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
backupTarget.app = client;
- doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
- doReturn(null).when(sService.mBackupTargets).get(anyInt());
+ doReturn(null).when(mService.mBackupTargets).get(anyInt());
assertEquals(BACKUP_APP_ADJ, app.mState.getSetAdj());
assertNoBfsl(app);
@@ -1236,7 +1271,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
client.mState.setRunningRemoteAnimation(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_LOW_APP_ADJ, app.mState.getSetAdj());
@@ -1251,7 +1286,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_NOT_VISIBLE, mock(IBinder.class));
client.mState.setRunningRemoteAnimation(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1266,7 +1301,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, 0, mock(IBinder.class));
client.mState.setHasOverlayUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1284,12 +1319,12 @@
Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
{
@@ -1303,13 +1338,13 @@
Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
doReturn(false).when(wpc).isHeavyWeightProcess();
assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
{
@@ -1321,12 +1356,12 @@
Context.BIND_ALMOST_PERCEPTIBLE,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
{
@@ -1340,13 +1375,13 @@
Context.BIND_ALMOST_PERCEPTIBLE,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
doReturn(false).when(wpc).isHeavyWeightProcess();
assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
}
@@ -1359,7 +1394,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, 0, mock(IBinder.class));
client.mState.setRunningRemoteAnimation(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(VISIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1375,7 +1410,7 @@
bindService(app, client, null, null, Context.BIND_IMPORTANT_BACKGROUND,
mock(IBinder.class));
client.mState.setHasOverlayUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_IMPORTANT_BACKGROUND, app.mState.getSetProcState());
@@ -1402,7 +1437,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindProvider(app, client, null, null, false);
client.mServices.setTreatLikeActivity(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
@@ -1416,11 +1451,11 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindProvider(app, client, null, null, false);
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_BOUND_TOP, FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT);
}
@@ -1434,7 +1469,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindProvider(app, client, null, null, false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1452,7 +1487,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
- ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
@@ -1464,7 +1499,7 @@
client.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
/* hasNoneType=*/false);
bindProvider(app, client, null, null, false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
// Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1486,7 +1521,7 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindProvider(app, client, null, null, true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, FOREGROUND_APP_ADJ,
@@ -1499,11 +1534,25 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.mProviders.setLastProviderTime(SystemClock.uptimeMillis());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
- SCHED_GROUP_BACKGROUND);
+ SCHED_GROUP_BACKGROUND, "recent-provider");
+
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND,
+ "cch-empty");
+ // Follow up should not have been called again.
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
}
@SuppressWarnings("GuardedBy")
@@ -1517,11 +1566,11 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client, client2, null, null, 0, mock(IBinder.class));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client2).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client2).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
@@ -1539,7 +1588,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(app, client2, null, null, 0, mock(IBinder.class));
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1559,7 +1608,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client, client2, null, null, 0, mock(IBinder.class));
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1584,7 +1633,7 @@
// Note: We add processes to LRU but still call updateOomAdjLocked() with a specific
// processes.
setProcessesToLru(app, client, client2);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1598,7 +1647,7 @@
assertBfsl(client2);
client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client2);
assertEquals(PROCESS_STATE_CACHED_EMPTY, client2.mState.getSetProcState());
@@ -1622,7 +1671,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client2, client, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1649,7 +1698,7 @@
bindService(client, client2, null, null, 0, mock(IBinder.class));
bindService(client2, client, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1683,7 +1732,7 @@
bindService(client3, client4, null, null, 0, mock(IBinder.class));
bindService(client4, client3, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1720,7 +1769,7 @@
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.mState.setForcingToImportant(new Object());
bindService(app, client3, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1746,7 +1795,7 @@
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.mState.setForcingToImportant(new Object());
bindService(app, client3, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -1773,7 +1822,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
client4.mState.setForcingToImportant(new Object());
bindService(app, client4, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -1802,7 +1851,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
client4.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app, client4, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1828,7 +1877,7 @@
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.mState.setForcingToImportant(new Object());
bindService(app, client3, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, client3, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1848,7 +1897,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1869,7 +1918,7 @@
bindProvider(client, client2, null, null, false);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(client2, app, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1889,7 +1938,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1910,7 +1959,7 @@
bindProvider(client, client2, null, null, false);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindProvider(client2, app, null, null, false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1936,7 +1985,7 @@
client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client1, client2, app1, app2);
assertProcStates(app1, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -1957,7 +2006,7 @@
assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
updateOomAdj(client1, client2, app1, app2);
assertProcStates(app1, PROCESS_STATE_IMPORTANT_FOREGROUND, VISIBLE_APP_ADJ,
SCHED_GROUP_TOP_APP);
@@ -2028,9 +2077,9 @@
SCHED_GROUP_DEFAULT);
client2.mState.setHasOverlayUi(false);
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client2).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client2).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client2, app2);
assertProcStates(app2, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ,
@@ -2047,7 +2096,7 @@
client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
bindService(app1, client1, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
@@ -2068,7 +2117,7 @@
client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
bindService(app1, client1, null, null, Context.BIND_ALMOST_PERCEPTIBLE,
mock(IBinder.class));
@@ -2088,7 +2137,7 @@
app.setPendingFinishAttach(true);
app.mState.setHasForegroundActivities(false);
- sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+ mService.mOomAdjuster.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FOREGROUND_APP_ADJ,
@@ -2102,9 +2151,9 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.setPendingFinishAttach(true);
app.mState.setHasForegroundActivities(true);
- doReturn(app).when(sService).getTopApp();
+ doReturn(app).when(mService).getTopApp();
- sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+ mService.mOomAdjuster.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_TOP, FOREGROUND_APP_ADJ,
@@ -2124,10 +2173,10 @@
MOCKAPP4_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
final ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
- final UidRecord app1UidRecord = new UidRecord(MOCKAPP_UID, sService);
- final UidRecord app2UidRecord = new UidRecord(MOCKAPP2_UID, sService);
- final UidRecord app3UidRecord = new UidRecord(MOCKAPP5_UID, sService);
- final UidRecord clientUidRecord = new UidRecord(MOCKAPP3_UID, sService);
+ final UidRecord app1UidRecord = new UidRecord(MOCKAPP_UID, mService);
+ final UidRecord app2UidRecord = new UidRecord(MOCKAPP2_UID, mService);
+ final UidRecord app3UidRecord = new UidRecord(MOCKAPP5_UID, mService);
+ final UidRecord clientUidRecord = new UidRecord(MOCKAPP3_UID, mService);
app1.setUidRecord(app1UidRecord);
app2.setUidRecord(app2UidRecord);
app3.setUidRecord(app3UidRecord);
@@ -2137,7 +2186,7 @@
client1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
client2.mState.setForcingToImportant(new Object());
setProcessesToLru(app1, app2, app3, client1, client2);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
final ComponentName cn1 = ComponentName.unflattenFromString(
MOCKAPP_PACKAGENAME + "/.TestService");
@@ -2164,10 +2213,10 @@
c2s.startRequested = true;
try {
- sService.mOomAdjuster.mActiveUids.put(MOCKAPP_UID, app1UidRecord);
- sService.mOomAdjuster.mActiveUids.put(MOCKAPP2_UID, app2UidRecord);
- sService.mOomAdjuster.mActiveUids.put(MOCKAPP5_UID, app3UidRecord);
- sService.mOomAdjuster.mActiveUids.put(MOCKAPP3_UID, clientUidRecord);
+ mService.mOomAdjuster.mActiveUids.put(MOCKAPP_UID, app1UidRecord);
+ mService.mOomAdjuster.mActiveUids.put(MOCKAPP2_UID, app2UidRecord);
+ mService.mOomAdjuster.mActiveUids.put(MOCKAPP5_UID, app3UidRecord);
+ mService.mOomAdjuster.mActiveUids.put(MOCKAPP3_UID, clientUidRecord);
setServiceMap(s1, MOCKAPP_UID, cn1);
setServiceMap(s2, MOCKAPP2_UID, cn2);
@@ -2195,10 +2244,10 @@
app2UidRecord.setIdle(true);
app3UidRecord.setIdle(true);
clientUidRecord.setIdle(true);
- doReturn(ActivityManager.APP_START_MODE_DELAYED).when(sService)
+ doReturn(ActivityManager.APP_START_MODE_DELAYED).when(mService)
.getAppStartModeLOSP(anyInt(), any(String.class), anyInt(),
anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
- doNothing().when(sService.mServices)
+ doNothing().when(mService.mServices)
.scheduleServiceTimeoutLocked(any(ProcessRecord.class));
updateOomAdj(client1, client2, app1, app2, app3);
@@ -2206,11 +2255,11 @@
assertEquals(PROCESS_STATE_SERVICE, app1.mState.getSetProcState());
assertEquals(PROCESS_STATE_SERVICE, client2.mState.getSetProcState());
} finally {
- doCallRealMethod().when(sService)
+ doCallRealMethod().when(mService)
.getAppStartModeLOSP(anyInt(), any(String.class), anyInt(),
anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
- sService.mServices.mServiceMap.clear();
- sService.mOomAdjuster.mActiveUids.clear();
+ mService.mServices.mServiceMap.clear();
+ mService.mOomAdjuster.mActiveUids.clear();
}
}
@@ -2224,7 +2273,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
app2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -2244,7 +2293,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
app2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app, app2, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2268,7 +2317,7 @@
bindService(app2, app3, null, null, 0, mock(IBinder.class));
app3.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app3, app, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2, app3);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2313,7 +2362,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app, app5, null, s, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2, app3, app4, app5);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2355,7 +2404,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app, app5, null, s, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app5, app4, app3, app2, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2397,7 +2446,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app, app5, null, s, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app3, app4, app2, app, app5);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2437,7 +2486,7 @@
client3.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
bindService(app, client3, null, null, Context.BIND_INCLUDE_CAPABILITIES,
mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
final int expected = PROCESS_CAPABILITY_ALL & ~PROCESS_CAPABILITY_BFSL;
@@ -2468,7 +2517,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindProvider(app, app5, cr, null, false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2, app3, app4, app5);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2512,8 +2561,8 @@
doCallRealMethod().when(s).getConnections();
s.startRequested = true;
s.lastActivity = now;
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.mNumServiceProcs = 3;
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mOomAdjuster.mNumServiceProcs = 3;
updateOomAdj(app3, app2, app);
assertEquals(SERVICE_B_ADJ, app3.mState.getSetAdj());
@@ -2530,15 +2579,15 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
final int userOwner = 0;
final int userOther = 1;
- final int cachedAdj1 = sService.mConstants.USE_TIERED_CACHED_ADJ
+ final int cachedAdj1 = mService.mConstants.USE_TIERED_CACHED_ADJ
? CACHED_APP_MIN_ADJ + 10
: CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
- final int cachedAdj2 = sService.mConstants.USE_TIERED_CACHED_ADJ
+ final int cachedAdj2 = mService.mConstants.USE_TIERED_CACHED_ADJ
? CACHED_APP_MIN_ADJ + 10
: cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
- doReturn(userOwner).when(sService.mUserController).getCurrentUserId();
+ doReturn(userOwner).when(mService.mUserController).getCurrentUserId();
- final ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
+ final ArrayList<ProcessRecord> lru = mService.mProcessList.getLruProcessesLOSP();
lru.clear();
lru.add(app2);
lru.add(app);
@@ -2549,10 +2598,10 @@
MOCKAPP2_PACKAGENAME + "/.TestService");
final long now = SystemClock.uptimeMillis();
- sService.mConstants.KEEP_WARMING_SERVICES.clear();
+ mService.mConstants.KEEP_WARMING_SERVICES.clear();
final ServiceInfo si = mock(ServiceInfo.class);
si.applicationInfo = mock(ApplicationInfo.class);
- ServiceRecord s = spy(new ServiceRecord(sService, cn, cn, null, 0, null,
+ ServiceRecord s = spy(new ServiceRecord(mService, cn, cn, null, 0, null,
si, false, null));
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
s.startRequested = true;
@@ -2564,16 +2613,16 @@
final ServiceInfo si2 = mock(ServiceInfo.class);
si2.applicationInfo = mock(ApplicationInfo.class);
si2.applicationInfo.uid = MOCKAPP2_UID_OTHER;
- ServiceRecord s2 = spy(new ServiceRecord(sService, cn2, cn2, null, 0, null,
+ ServiceRecord s2 = spy(new ServiceRecord(mService, cn2, cn2, null, 0, null,
si2, false, null));
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s2).getConnections();
s2.startRequested = true;
- s2.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+ s2.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
app2.mServices.startService(s2);
app2.mState.setHasShownUi(false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-ui-services");
@@ -2590,7 +2639,7 @@
app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
- s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+ s.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
updateOomAdj();
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
@@ -2600,9 +2649,9 @@
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
app.mState.setHasShownUi(true);
- sService.mConstants.KEEP_WARMING_SERVICES.add(cn);
- sService.mConstants.KEEP_WARMING_SERVICES.add(cn2);
- s = spy(new ServiceRecord(sService, cn, cn, null, 0, null,
+ mService.mConstants.KEEP_WARMING_SERVICES.add(cn);
+ mService.mConstants.KEEP_WARMING_SERVICES.add(cn2);
+ s = spy(new ServiceRecord(mService, cn, cn, null, 0, null,
si, false, null));
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
s.startRequested = true;
@@ -2618,14 +2667,14 @@
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
app.mState.setHasShownUi(false);
- s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+ s.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
updateOomAdj();
assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
- doReturn(userOther).when(sService.mUserController).getCurrentUserId();
- sService.mOomAdjuster.handleUserSwitchedLocked();
+ doReturn(userOther).when(mService.mUserController).getCurrentUserId();
+ mService.mOomAdjuster.handleUserSwitchedLocked();
updateOomAdj();
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
@@ -2637,9 +2686,9 @@
public void testUpdateOomAdj_DoOne_AboveClient_SameProcess() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(app).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(app).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -2672,8 +2721,8 @@
s = bindService(app3, app2, null, null, 0, mock(IBinder.class));
s.lastActivity = now;
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.mNumServiceProcs = 3;
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mOomAdjuster.mNumServiceProcs = 3;
updateOomAdj(app, app2, app3);
assertEquals(SERVICE_ADJ, app.mState.getSetAdj());
@@ -2688,9 +2737,9 @@
public void testUpdateOomAdj_DoOne_AboveClient_NotStarted() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(app).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(app).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -2718,7 +2767,7 @@
ServiceRecord s = makeServiceRecord(app);
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -2738,7 +2787,7 @@
ServiceRecord s = makeServiceRecord(app);
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdjPending(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -2760,7 +2809,7 @@
ServiceRecord s = makeServiceRecord(app);
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -2781,7 +2830,7 @@
ServiceRecord s = makeServiceRecord(app);
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdjPending(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -2809,7 +2858,7 @@
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
attributedClient.mServices.setHasForegroundServices(true, 0, true);
bindService(sandboxService, client, attributedClient, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(client, PROCESS_STATE_PERSISTENT, PERSISTENT_PROC_ADJ,
SCHED_GROUP_DEFAULT);
@@ -2830,13 +2879,13 @@
// App1 binds to app2 and gets temp allowlisted.
bindService(app2, app, null, null, 0, mock(IBinder.class));
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
assertEquals(true, app.getUidRecord().isSetAllowListed());
assertEquals(true, app.mOptRecord.shouldNotFreeze());
assertEquals(true, app2.mOptRecord.shouldNotFreeze());
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertEquals(false, app.mOptRecord.shouldNotFreeze());
assertEquals(false, app2.mOptRecord.shouldNotFreeze());
@@ -2856,8 +2905,8 @@
// App1 and app2 both bind to app3 and get temp allowlisted.
bindService(app3, app, null, null, 0, mock(IBinder.class));
bindService(app3, app2, null, null, 0, mock(IBinder.class));
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, true);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, true);
assertEquals(true, app.getUidRecord().isSetAllowListed());
assertEquals(true, app2.getUidRecord().isSetAllowListed());
@@ -2866,7 +2915,7 @@
assertEquals(true, app3.mOptRecord.shouldNotFreeze());
// Remove app1 from allowlist.
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertEquals(true, app2.getUidRecord().isSetAllowListed());
assertEquals(false, app.mOptRecord.shouldNotFreeze());
@@ -2874,7 +2923,7 @@
assertEquals(true, app3.mOptRecord.shouldNotFreeze());
// Now remove app2 from allowlist.
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, false);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertEquals(false, app2.getUidRecord().isSetAllowListed());
assertEquals(false, app.mOptRecord.shouldNotFreeze());
@@ -2882,6 +2931,73 @@
assertEquals(false, app3.mOptRecord.shouldNotFreeze());
}
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testUpdateOomAdj_DoAll_ClientlessService() {
+ ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+
+ setProcessesToLru(app);
+ ServiceRecord s = makeServiceRecord(app);
+ s.startRequested = true;
+ s.lastActivity = SystemClock.uptimeMillis();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ updateOomAdj();
+ assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
+ "started-services");
+
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler).sendEmptyMessageAtTime(
+ eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertProcStates(app, PROCESS_STATE_SERVICE, sFirstCachedAdj, SCHED_GROUP_BACKGROUND,
+ "cch-started-services");
+ // Follow up should not have been called again.
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testUpdateOomAdj_DoAll_Multiple_Provider_Retention() {
+ ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+ ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+ MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ app1.mProviders.setLastProviderTime(SystemClock.uptimeMillis());
+ app2.mProviders.setLastProviderTime(SystemClock.uptimeMillis() + 2000);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setProcessesToLru(app1, app2);
+ mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+
+ assertProcStates(app1, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
+ SCHED_GROUP_BACKGROUND, "recent-provider");
+ assertProcStates(app2, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
+ SCHED_GROUP_BACKGROUND, "recent-provider");
+
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler, atLeastOnce()).sendEmptyMessageAtTime(
+ eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertProcStates(app1, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND,
+ "cch-empty");
+
+ verify(mService.mHandler, atLeastOnce()).sendEmptyMessageAtTime(
+ eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ assertProcStates(app2, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND,
+ "cch-empty");
+ }
+
private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
String packageName, boolean hasShownUi) {
return new ProcessRecordBuilder(pid, uid, processName, packageName).setHasShownUi(
@@ -2904,7 +3020,7 @@
}
private void setServiceMap(ServiceRecord s, int uid, ComponentName cn) {
- ActiveServices.ServiceMap serviceMap = sService.mServices.mServiceMap.get(
+ ActiveServices.ServiceMap serviceMap = mService.mServices.mServiceMap.get(
UserHandle.getUserId(uid));
if (serviceMap == null) {
serviceMap = mock(ActiveServices.ServiceMap.class);
@@ -2916,7 +3032,7 @@
new ArrayMap<>());
setFieldValue(ActiveServices.ServiceMap.class, serviceMap, "mDelayedStartList",
new ArrayList<>());
- sService.mServices.mServiceMap.put(UserHandle.getUserId(uid), serviceMap);
+ mService.mServices.mServiceMap.put(UserHandle.getUserId(uid), serviceMap);
}
serviceMap.mServicesByInstanceName.put(cn, s);
}
@@ -2957,6 +3073,7 @@
return record;
}
+ @SuppressWarnings("GuardedBy")
private void assertProcStates(ProcessRecord app, int expectedProcState, int expectedAdj,
int expectedSchedGroup) {
final ProcessStateRecord state = app.mState;
@@ -2974,6 +3091,7 @@
}
}
+ @SuppressWarnings("GuardedBy")
private void assertProcStates(ProcessRecord app, boolean expectedCached,
int expectedProcState, int expectedAdj, String expectedAdjType) {
final ProcessStateRecord state = app.mState;
@@ -2992,7 +3110,26 @@
}
}
- private static class ProcessRecordBuilder {
+ @SuppressWarnings("GuardedBy")
+ private void assertProcStates(ProcessRecord app, int expectedProcState, int expectedAdj,
+ int expectedSchedGroup, String expectedAdjType) {
+ final ProcessStateRecord state = app.mState;
+ assertEquals(expectedAdjType, state.getAdjType());
+ assertEquals(expectedProcState, state.getSetProcState());
+ assertEquals(expectedAdj, state.getSetAdj());
+ assertEquals(expectedSchedGroup, state.getSetSchedGroup());
+
+ // Below BFGS should never have BFSL.
+ if (expectedProcState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ assertNoBfsl(app);
+ }
+ // Above FGS should always have BFSL.
+ if (expectedProcState < PROCESS_STATE_FOREGROUND_SERVICE) {
+ assertBfsl(app);
+ }
+ }
+
+ private class ProcessRecordBuilder {
@SuppressWarnings("UnusedVariable")
int mPid;
int mUid;
@@ -3069,17 +3206,17 @@
ai.packageName = mPackageName;
ai.longVersionCode = mVersionCode;
ai.targetSdkVersion = mTargetSdkVersion;
- doCallRealMethod().when(sService).getPackageManagerInternal();
- doReturn(null).when(sPackageManagerInternal).getApplicationInfo(
+ doCallRealMethod().when(mService).getPackageManagerInternal();
+ doReturn(null).when(mPackageManagerInternal).getApplicationInfo(
eq(mSdkSandboxClientAppPackage), anyLong(), anyInt(), anyInt());
- ProcessRecord app = new ProcessRecord(sService, ai, mProcessName, mUid,
+ ProcessRecord app = new ProcessRecord(mService, ai, mProcessName, mUid,
mSdkSandboxClientAppPackage, -1, null);
final ProcessStateRecord state = app.mState;
final ProcessServiceRecord services = app.mServices;
final ProcessReceiverRecord receivers = app.mReceivers;
final ProcessProfileRecord profile = app.mProfile;
final ProcessProviderRecord providers = app.mProviders;
- app.makeActive(mock(IApplicationThread.class), sService.mProcessStats);
+ app.makeActive(mock(IApplicationThread.class), mService.mProcessStats);
app.setLastActivityTime(mLastActivityTime);
app.setKilledByAm(mKilledByAm);
app.setIsolatedEntryPoint(mIsolatedEntryPoint);
@@ -3124,14 +3261,35 @@
}
providers.setLastProviderTime(mLastProviderTime);
- UidRecord uidRec = sService.mOomAdjuster.mActiveUids.get(mUid);
+ UidRecord uidRec = mService.mOomAdjuster.mActiveUids.get(mUid);
if (uidRec == null) {
- uidRec = new UidRecord(mUid, sService);
- sService.mOomAdjuster.mActiveUids.put(mUid, uidRec);
+ uidRec = new UidRecord(mUid, mService);
+ mService.mOomAdjuster.mActiveUids.put(mUid, uidRec);
}
uidRec.addProcess(app);
app.setUidRecord(uidRec);
return app;
}
}
+
+ static class OomAdjusterInjector extends OomAdjuster.Injector {
+ // Jump ahead in time by this offset amount.
+ long mTimeOffsetMillis = 0;
+
+ void jumpUptimeAheadTo(long uptimeMillis) {
+ final long jumpMs = uptimeMillis - getUptimeMillis();
+ if (jumpMs <= 0) return;
+ mTimeOffsetMillis += jumpMs;
+ }
+
+ @Override
+ long getUptimeMillis() {
+ return SystemClock.uptimeMillis() + mTimeOffsetMillis;
+ }
+
+ @Override
+ long getElapsedRealtimeMillis() {
+ return SystemClock.elapsedRealtime() + mTimeOffsetMillis;
+ }
+ }
}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index ce2bb95..4460c6a 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -31,7 +31,6 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
-import android.app.AppOpsManager;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.SensorManager;
@@ -42,6 +41,7 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.os.test.TestLooper;
@@ -82,12 +82,8 @@
@Mock private StatusBarManagerInternal mStatusBarManagerInternal;
@Mock private WakeLockLog mWakeLockLog;
- @Mock private IBatteryStats mBatteryStats;
-
@Mock private PowerManagerFlags mPowerManagerFlags;
- @Mock private AppOpsManager mAppOpsManager;
-
private PowerManagerService mService;
private Context mContextSpy;
private Resources mResourcesSpy;
@@ -234,7 +230,7 @@
public void testOnWakeLockListener_RemoteException_NoRethrow() {
when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
createNotifier();
- clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
@Override public void onStateChanged(boolean enabled) throws RemoteException {
throw new RemoteException("Just testing");
@@ -249,7 +245,6 @@
verifyZeroInteractions(mWakeLockLog);
mTestLooper.dispatchAll();
verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, 1);
-
mNotifier.onWakeLockAcquired(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
"my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
exceptingCallback);
@@ -282,115 +277,6 @@
verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
}
-
- @Test
- public void testOnWakeLockListener_FullWakeLock_ProcessesOnHandler() throws RemoteException {
- when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
- createNotifier();
-
- IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
- @Override public void onStateChanged(boolean enabled) throws RemoteException {
- throw new RemoteException("Just testing");
- }
- };
- clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
-
- final int uid = 1234;
- final int pid = 5678;
-
- // Release the wakelock
- mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
- "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
- exceptingCallback);
-
- // No interaction because we expect that to happen in async
- verifyZeroInteractions(mWakeLockLog, mBatteryStats, mAppOpsManager);
-
- // Progressing the looper, and validating all the interactions
- mTestLooper.dispatchAll();
- verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, 1);
- verify(mBatteryStats).noteStopWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
- BatteryStats.WAKE_TYPE_FULL);
- verify(mAppOpsManager).finishOp(AppOpsManager.OP_WAKE_LOCK, uid,
- "my.package.name", null);
-
- clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
-
- // Acquire the wakelock
- mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
- "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
- exceptingCallback);
-
- // No interaction because we expect that to happen in async
- verifyNoMoreInteractions(mWakeLockLog, mBatteryStats, mAppOpsManager);
-
- // Progressing the looper, and validating all the interactions
- mTestLooper.dispatchAll();
- verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
- PowerManager.SCREEN_BRIGHT_WAKE_LOCK, 1);
- verify(mBatteryStats).noteStartWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
- BatteryStats.WAKE_TYPE_FULL, false);
- verify(mAppOpsManager).startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, uid,
- "my.package.name", false, null, null);
-
- // Test with improveWakelockLatency flag false, hence the wakelock log will run on the same
- // thread
- clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
- when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(false);
-
- mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
- "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
- exceptingCallback);
- verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
- PowerManager.SCREEN_BRIGHT_WAKE_LOCK, -1);
-
- mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
- "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
- exceptingCallback);
- verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
- }
-
- @Test
- public void testOnWakeLockListener_FullWakeLock_ProcessesInSync() throws RemoteException {
- createNotifier();
-
- IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
- @Override public void onStateChanged(boolean enabled) throws RemoteException {
- throw new RemoteException("Just testing");
- }
- };
- clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
-
- final int uid = 1234;
- final int pid = 5678;
-
- // Release the wakelock
- mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
- "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
- exceptingCallback);
-
- verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
- verify(mBatteryStats).noteStopWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
- BatteryStats.WAKE_TYPE_FULL);
- verify(mAppOpsManager).finishOp(AppOpsManager.OP_WAKE_LOCK, uid,
- "my.package.name", null);
-
- clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
-
- // Acquire the wakelock
- mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
- "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
- exceptingCallback);
-
- mTestLooper.dispatchAll();
- verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
- PowerManager.SCREEN_BRIGHT_WAKE_LOCK, -1);
- verify(mBatteryStats).noteStartWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
- BatteryStats.WAKE_TYPE_FULL, false);
- verify(mAppOpsManager).startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, uid,
- "my.package.name", false, null, null);
- }
-
private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() {
@Override
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
@@ -479,17 +365,13 @@
public WakeLockLog getWakeLockLog(Context context) {
return mWakeLockLog;
}
-
- @Override
- public AppOpsManager getAppOpsManager(Context context) {
- return mAppOpsManager;
- }
};
mNotifier = new Notifier(
mTestLooper.getLooper(),
mContextSpy,
- mBatteryStats,
+ IBatteryStats.Stub.asInterface(ServiceManager.getService(
+ BatteryStats.SERVICE_NAME)),
mInjector.createSuspendBlocker(mService, "testBlocker"),
null,
null,
diff --git a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
index 8cbed2c..31bf5f0 100644
--- a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
@@ -61,20 +61,6 @@
private static final long USAGE_STATS_INTERACTION = 10 * 60 * 1000L;
private static final long SERVICE_USAGE_INTERACTION = 60 * 1000;
- static class MyOomAdjuster extends OomAdjuster {
-
- MyOomAdjuster(ActivityManagerService service, ProcessList processList,
- ActiveUids activeUids) {
- super(service, processList, activeUids);
- }
-
- @Override
- protected boolean isChangeEnabled(int changeId, ApplicationInfo app,
- boolean defaultValue) {
- return true;
- }
- }
-
@BeforeClass
public static void setUpOnce() {
sContext = getInstrumentation().getTargetContext();
@@ -99,7 +85,15 @@
final AppProfiler profiler = mock(AppProfiler.class);
setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
setFieldValue(ActivityManagerService.class, sService, "mAppProfiler", profiler);
- sService.mOomAdjuster = new MyOomAdjuster(sService, sService.mProcessList, null);
+ final OomAdjuster.Injector injector = new OomAdjuster.Injector(){
+ @Override
+ boolean isChangeEnabled(int changeId, ApplicationInfo app,
+ boolean defaultValue) {
+ return true;
+ }
+ };
+ sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList, null,
+ injector);
LocalServices.addService(UsageStatsManagerInternal.class,
mock(UsageStatsManagerInternal.class));
sService.mUsageStatsService = LocalServices.getService(UsageStatsManagerInternal.class);
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 3cab75b..3d68849 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -18,11 +18,13 @@
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.NETWORK_STACK;
+import static android.app.ActivityManager.MAX_PROCESS_STATE;
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
@@ -165,9 +167,11 @@
import android.os.PowerSaveState;
import android.os.RemoteException;
import android.os.SimpleClock;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
+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;
@@ -2158,7 +2162,8 @@
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
- public void testBackgroundChainOnProcStateChange() throws Exception {
+ @RequiresFlagsDisabled(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN)
+ public void testBackgroundChainOnProcStateChangeSameDelay() throws Exception {
// initialization calls setFirewallChainEnabled, so we want to reset the invocations.
clearInvocations(mNetworkManager);
@@ -2186,6 +2191,59 @@
}
@Test
+ @RequiresFlagsEnabled({
+ Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE,
+ Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN
+ })
+ public void testBackgroundChainOnProcStateChangeDifferentDelays() throws Exception {
+ // The app will be blocked when there is no prior proc-state.
+ assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
+
+ // Tweak delays to avoid waiting too long in tests.
+ mService.mBackgroundRestrictionShortDelayMs = 50;
+ mService.mBackgroundRestrictionLongDelayMs = 1000;
+
+ int procStateSeq = 231; // Any arbitrary starting sequence.
+ for (int ps = BACKGROUND_THRESHOLD_STATE; ps <= MAX_PROCESS_STATE; ps++) {
+ clearInvocations(mNetworkManager);
+
+ // Make sure app is in correct process-state to access network.
+ callAndWaitOnUidStateChanged(UID_A, BACKGROUND_THRESHOLD_STATE - 1, procStateSeq++);
+ verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A,
+ FIREWALL_RULE_ALLOW);
+ assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
+
+ // Now put the app into the background and test that it eventually loses network.
+ callAndWaitOnUidStateChanged(UID_A, ps, procStateSeq++);
+
+ final long uidStateChangeTime = SystemClock.uptimeMillis();
+ if (ps <= PROCESS_STATE_LAST_ACTIVITY) {
+ // Verify that the app is blocked after long delay but not after short delay.
+ waitForDelayedMessageOnHandler(mService.mBackgroundRestrictionShortDelayMs + 1);
+ verify(mNetworkManager, never()).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND,
+ UID_A, FIREWALL_RULE_DEFAULT);
+ assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
+
+ final long timeUntilLongDelay = uidStateChangeTime
+ + mService.mBackgroundRestrictionLongDelayMs - SystemClock.uptimeMillis();
+ assertTrue("No time left to verify long delay in background transition",
+ timeUntilLongDelay >= 0);
+
+ waitForDelayedMessageOnHandler(timeUntilLongDelay + 1);
+ verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A,
+ FIREWALL_RULE_DEFAULT);
+ assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
+ } else {
+ // Verify that the app is blocked after short delay.
+ waitForDelayedMessageOnHandler(mService.mBackgroundRestrictionShortDelayMs + 1);
+ verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A,
+ FIREWALL_RULE_DEFAULT);
+ assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
+ }
+ }
+ }
+
+ @Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testBackgroundChainOnAllowlistChange() throws Exception {
// initialization calls setFirewallChainEnabled, so we want to reset the invocations.
@@ -2881,6 +2939,11 @@
}
}
+ /**
+ * This posts a blocking message to the service handler with the given delayMs and waits for it
+ * to complete. This ensures that all messages posted before the given delayMs will also
+ * have been executed before this method returns and can be verified in subsequent code.
+ */
private void waitForDelayedMessageOnHandler(long delayMs) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
mService.getHandlerForTesting().postDelayed(latch::countDown, delayMs);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index abfb95c..9352c12 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -17,7 +17,16 @@
package com.android.server.notification;
import static android.app.AutomaticZenRule.TYPE_BEDTIME;
+import static android.app.Flags.FLAG_MODES_UI;
+import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+import static android.provider.Settings.Global.ZEN_MODE_OFF;
+import static android.service.notification.Condition.SOURCE_USER_ACTION;
+import static android.service.notification.Condition.STATE_FALSE;
+import static android.service.notification.Condition.STATE_TRUE;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
+import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_NONE;
+import static android.service.notification.ZenPolicy.PEOPLE_TYPE_ANYONE;
+import static android.service.notification.ZenPolicy.STATE_ALLOW;
import static com.google.common.truth.Truth.assertThat;
@@ -33,6 +42,9 @@
import android.content.ComponentName;
import android.net.Uri;
import android.os.Parcel;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.service.notification.Condition;
@@ -43,7 +55,6 @@
import android.util.Xml;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -63,9 +74,13 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.Instant;
+import java.util.List;
+
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(ParameterizedAndroidJunit4.class)
public class ZenModeConfigTest extends UiServiceTestCase {
private final String NAME = "name";
@@ -91,6 +106,16 @@
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(
SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);
+ @Parameters(name = "{0}")
+ public static List<FlagsParameterization> getParams() {
+ return FlagsParameterization.allCombinationsOf(
+ FLAG_MODES_UI);
+ }
+
+ public ZenModeConfigTest(FlagsParameterization flags) {
+ mSetFlagsRule.setFlagsParameterization(flags);
+ }
+
@Before
public final void setUp() {
mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
@@ -101,13 +126,44 @@
ZenModeConfig config = getMutedRingerConfig();
assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
- config.allowReminders = true;
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
+ .allowReminders(true)
+ .build();
+ } else {
+ config.setAllowReminders(true);
+ }
assertFalse(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
- config.allowReminders = false;
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
+ .allowReminders(false)
+ .build();
+ } else {
+ config.setAllowReminders(false);
+ }
+ assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
config.areChannelsBypassingDnd = true;
+ assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
+
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
+ .allowPriorityChannels(true)
+ .build();
+ } else {
+ config.setAllowPriorityChannels(true);
+ }
+
assertFalse(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
+
config.areChannelsBypassingDnd = false;
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
+ .allowPriorityChannels(false)
+ .build();
+ } else {
+ config.setAllowPriorityChannels(false);
+ }
assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
}
@@ -122,6 +178,8 @@
@Test
public void testZenPolicyToNotificationPolicy_classic() {
ZenModeConfig config = getMutedAllConfig();
+ // this shouldn't usually be directly set, but since it's a test that involved the default
+ // policy, calling setNotificationPolicy as a precondition may obscure issues
config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
// Explicitly allow conversations from priority senders to make sure that goes through
@@ -154,8 +212,9 @@
@Test
public void testZenPolicyToNotificationPolicy() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
ZenModeConfig config = getMutedAllConfig();
+ // this shouldn't usually be directly set, but since it's a test that involved the default
+ // policy, calling setNotificationPolicy as a precondition may obscure issues
config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
// Explicitly allow conversations from priority senders to make sure that goes through
@@ -194,14 +253,16 @@
@Test
public void testZenPolicyToNotificationPolicy_unsetChannelsTakesDefault() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
ZenModeConfig config = new ZenModeConfig();
ZenPolicy zenPolicy = new ZenPolicy.Builder().build();
// When allowChannels is not set to anything in the ZenPolicy builder, make sure it takes
// the default value from the zen mode config.
Policy policy = config.toNotificationPolicy(zenPolicy);
- assertEquals(config.allowPriorityChannels, policy.allowPriorityChannels());
+ assertEquals(Flags.modesUi()
+ ? config.manualRule.zenPolicy.getPriorityChannelsAllowed() == STATE_ALLOW
+ : config.isAllowPriorityChannels(),
+ policy.allowPriorityChannels());
}
@Test
@@ -219,18 +280,22 @@
.build();
ZenModeConfig config = getMutedAllConfig();
- config.allowAlarms = true;
- config.allowReminders = true;
- config.allowEvents = true;
- config.allowCalls = true;
- config.allowCallsFrom = Policy.PRIORITY_SENDERS_CONTACTS;
- config.allowMessages = true;
- config.allowMessagesFrom = Policy.PRIORITY_SENDERS_STARRED;
- config.allowConversations = false;
- config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
- config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
- config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
- ZenPolicy actual = config.toZenPolicy();
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = expected.copy();
+ } else {
+ config.setAllowAlarms(true);
+ config.setAllowReminders(true);
+ config.setAllowEvents(true);
+ config.setAllowCalls(true);
+ config.setAllowCallsFrom(Policy.PRIORITY_SENDERS_CONTACTS);
+ config.setAllowMessages(true);
+ config.setAllowMessagesFrom(Policy.PRIORITY_SENDERS_STARRED);
+ config.setAllowConversationsFrom(CONVERSATION_SENDERS_NONE);
+ config.setSuppressedVisualEffects(config.getSuppressedVisualEffects()
+ | Policy.SUPPRESSED_EFFECT_BADGE | Policy.SUPPRESSED_EFFECT_LIGHTS
+ | Policy.SUPPRESSED_EFFECT_AMBIENT);
+ }
+ ZenPolicy actual = config.getZenPolicy();
assertEquals(expected.getVisualEffectBadge(), actual.getVisualEffectBadge());
assertEquals(expected.getPriorityCategoryAlarms(), actual.getPriorityCategoryAlarms());
@@ -247,7 +312,6 @@
@Test
public void testZenConfigToZenPolicy() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
ZenPolicy expected = new ZenPolicy.Builder()
.allowAlarms(true)
.allowReminders(true)
@@ -262,19 +326,24 @@
.build();
ZenModeConfig config = getMutedAllConfig();
- config.allowAlarms = true;
- config.allowReminders = true;
- config.allowEvents = true;
- config.allowCalls = true;
- config.allowCallsFrom = Policy.PRIORITY_SENDERS_CONTACTS;
- config.allowMessages = true;
- config.allowMessagesFrom = Policy.PRIORITY_SENDERS_STARRED;
- config.allowConversations = false;
- config.allowPriorityChannels = false;
- config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
- config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
- config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
- ZenPolicy actual = config.toZenPolicy();
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = expected.copy();
+ } else {
+ config.setAllowAlarms(true);
+ config.setAllowReminders(true);
+
+ config.setAllowEvents(true);
+ config.setAllowCalls(true);
+ config.setAllowCallsFrom(Policy.PRIORITY_SENDERS_CONTACTS);
+ config.setAllowMessages(true);
+ config.setAllowMessagesFrom(Policy.PRIORITY_SENDERS_STARRED);
+ config.setAllowConversationsFrom(CONVERSATION_SENDERS_NONE);
+ config.setAllowPriorityChannels(false);
+ config.setSuppressedVisualEffects(config.getSuppressedVisualEffects()
+ | Policy.SUPPRESSED_EFFECT_BADGE | Policy.SUPPRESSED_EFFECT_LIGHTS
+ | Policy.SUPPRESSED_EFFECT_AMBIENT);
+ }
+ ZenPolicy actual = config.getZenPolicy();
assertEquals(expected.getVisualEffectBadge(), actual.getVisualEffectBadge());
assertEquals(expected.getPriorityCategoryAlarms(), actual.getPriorityCategoryAlarms());
@@ -296,20 +365,64 @@
assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
assertTrue(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
- config.allowReminders = true;
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
+ .allowReminders(true)
+ .build();
+ } else {
+ config.setAllowReminders(true);
+ }
assertFalse(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
assertFalse(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
- config.allowReminders = false;
+
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
+ .allowReminders(false)
+ .build();
+ } else {
+ config.setAllowReminders(false);
+ }
+
+ assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
+ assertTrue(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
config.areChannelsBypassingDnd = true;
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
+ .allowPriorityChannels(true)
+ .build();
+ } else {
+ config.setAllowPriorityChannels(true);
+ }
+
assertFalse(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
assertFalse(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
- config.areChannelsBypassingDnd = false;
- config.allowAlarms = true;
+ config.areChannelsBypassingDnd = false;
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
+ .allowPriorityChannels(false)
+ .build();
+ } else {
+ config.setAllowPriorityChannels(false);
+ }
+
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
+ .allowAlarms(true)
+ .build();
+ } else {
+ config.setAllowAlarms(true);
+ }
assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
assertFalse(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
- config.allowAlarms = false;
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder(config.manualRule.zenPolicy)
+ .allowAlarms(false)
+ .build();
+ } else {
+ config.setAllowAlarms(false);
+ }
assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
assertTrue(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
@@ -375,8 +488,6 @@
@Test
public void testWriteToParcel() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.configurationActivity = CONFIG_ACTIVITY;
rule.component = OWNER;
@@ -473,8 +584,6 @@
@Test
public void testRuleXml() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.configurationActivity = CONFIG_ACTIVITY;
rule.component = OWNER;
@@ -719,8 +828,6 @@
@Test
public void testZenPolicyXml() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenPolicy policy = new ZenPolicy.Builder()
.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
.allowMessages(ZenPolicy.PEOPLE_TYPE_NONE)
@@ -770,63 +877,173 @@
fromXml.getVisualEffectNotificationList());
}
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_UI)
+ public void testisManualActive_stateTrue() {
+ ZenModeConfig config = getMutedAllConfig();
+ final ZenModeConfig.ZenRule newRule = new ZenModeConfig.ZenRule();
+ newRule.type = AutomaticZenRule.TYPE_OTHER;
+ newRule.enabled = true;
+ newRule.conditionId = Uri.EMPTY;
+ newRule.allowManualInvocation = true;
+ config.manualRule = newRule;
+ config.manualRule.pkg = "android";
+ config.manualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ config.manualRule.condition = new Condition(Uri.EMPTY, "", STATE_TRUE, SOURCE_USER_ACTION);
+
+ assertThat(config.isManualActive()).isTrue();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_UI)
+ public void testisManualActive_stateFalse() {
+ ZenModeConfig config = getMutedAllConfig();
+ final ZenModeConfig.ZenRule newRule = new ZenModeConfig.ZenRule();
+ newRule.type = AutomaticZenRule.TYPE_OTHER;
+ newRule.enabled = true;
+ newRule.conditionId = Uri.EMPTY;
+ newRule.allowManualInvocation = true;
+ config.manualRule = newRule;
+ config.manualRule.pkg = "android";
+ config.manualRule.zenMode = ZEN_MODE_OFF;
+ config.manualRule.condition = new Condition(Uri.EMPTY, "", STATE_FALSE, SOURCE_USER_ACTION);
+
+ assertThat(config.isManualActive()).isFalse();
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MODES_UI)
+ public void testisManualActive_noState() {
+ ZenModeConfig config = getMutedAllConfig();
+ final ZenModeConfig.ZenRule newRule = new ZenModeConfig.ZenRule();
+ newRule.type = AutomaticZenRule.TYPE_OTHER;
+ newRule.enabled = true;
+ newRule.conditionId = Uri.EMPTY;
+ newRule.allowManualInvocation = true;
+ config.manualRule = newRule;
+ config.manualRule.pkg = "android";
+ config.manualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+
+ assertThat(config.isManualActive()).isTrue();
+ }
+
+ @Test
+ public void testisManualActive_noRule() {
+ ZenModeConfig config = getMutedAllConfig();
+
+ assertThat(config.isManualActive()).isFalse();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_UI)
+ public void testRuleXml_manual_upgrade() throws Exception {
+ ZenModeConfig config = getMutedAllConfig();
+ final ZenModeConfig.ZenRule newRule = new ZenModeConfig.ZenRule();
+ newRule.type = AutomaticZenRule.TYPE_OTHER;
+ newRule.enabled = true;
+ newRule.conditionId = Uri.EMPTY;
+ newRule.allowManualInvocation = true;
+ newRule.pkg = "android";
+ newRule.zenMode = ZEN_MODE_OFF;
+ config.manualRule = newRule;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ writeRuleXml(newRule, baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ZenModeConfig.ZenRule fromXml = readRuleXml(bais);
+
+ assertThat(fromXml.zenPolicy).isEqualTo(config.getZenPolicy());
+ }
+
private ZenModeConfig getMutedRingerConfig() {
ZenModeConfig config = new ZenModeConfig();
- // Allow alarms, media
- config.allowAlarms = true;
- config.allowMedia = true;
- // All sounds that respect the ringer are not allowed
- config.allowSystem = false;
- config.allowCalls = false;
- config.allowRepeatCallers = false;
- config.allowMessages = false;
- config.allowReminders = false;
- config.allowEvents = false;
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder()
+ .disallowAllSounds()
+ .allowAlarms(true)
+ .allowMedia(true)
+ .allowPriorityChannels(false)
+ .showAllVisualEffects()
+ .build();
+ } else {
+ // Allow alarms, media
+ config.setAllowAlarms(true);
+ config.setAllowMedia(true);
+
+ // All sounds that respect the ringer are not allowed
+ config.setAllowSystem(false);
+ config.setAllowCalls(false);
+ config.setAllowRepeatCallers(false);
+ config.setAllowMessages(false);
+ config.setAllowReminders(false);
+ config.setAllowEvents(false);
+ config.setSuppressedVisualEffects(0);
+ config.setAllowPriorityChannels(false);
+ }
config.areChannelsBypassingDnd = false;
- config.suppressedVisualEffects = 0;
-
return config;
}
private ZenModeConfig getCustomConfig() {
ZenModeConfig config = new ZenModeConfig();
- // Some sounds allowed
- config.allowAlarms = true;
- config.allowMedia = false;
- config.allowSystem = false;
- config.allowCalls = true;
- config.allowRepeatCallers = true;
- config.allowMessages = false;
- config.allowReminders = false;
- config.allowEvents = false;
- config.areChannelsBypassingDnd = false;
- config.allowCallsFrom = ZenModeConfig.SOURCE_ANYONE;
- config.allowMessagesFrom = ZenModeConfig.SOURCE_ANYONE;
- config.allowConversations = true;
- config.allowConversationsFrom = CONVERSATION_SENDERS_IMPORTANT;
- config.suppressedVisualEffects = 0;
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder()
+ .disallowAllSounds()
+ .allowAlarms(true)
+ .allowCalls(PEOPLE_TYPE_ANYONE)
+ .allowRepeatCallers(true)
+ .allowConversations(CONVERSATION_SENDERS_IMPORTANT)
+ .allowPriorityChannels(true)
+ .showAllVisualEffects()
+ .build();
+ } else {
+ // Some sounds allowed
+ config.setAllowAlarms(true);
+ config.setAllowMedia(false);
+ config.setAllowSystem(false);
+ config.setAllowCalls(true);
+ config.setAllowRepeatCallers(true);
+ config.setAllowMessages(false);
+ config.setAllowReminders(false);
+ config.setAllowEvents(false);
+ config.setAllowCallsFrom(ZenModeConfig.SOURCE_ANYONE);
+ config.setAllowMessagesFrom(ZenModeConfig.SOURCE_ANYONE);
+ config.setAllowConversations(true);
+ config.setAllowConversationsFrom(CONVERSATION_SENDERS_IMPORTANT);
+ config.setSuppressedVisualEffects(0);
+ config.setAllowPriorityChannels(true);
+ }
+ config.areChannelsBypassingDnd = false;
return config;
}
private ZenModeConfig getMutedAllConfig() {
ZenModeConfig config = new ZenModeConfig();
- // No sounds allowed
- config.allowAlarms = false;
- config.allowMedia = false;
- config.allowSystem = false;
- config.allowCalls = false;
- config.allowRepeatCallers = false;
- config.allowMessages = false;
- config.allowReminders = false;
- config.allowEvents = false;
- config.areChannelsBypassingDnd = false;
- config.allowConversations = false;
- config.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_NONE;
- config.suppressedVisualEffects = 0;
+ if (Flags.modesUi()) {
+ config.manualRule.zenPolicy = new ZenPolicy.Builder()
+ .disallowAllSounds()
+ .showAllVisualEffects()
+ .allowPriorityChannels(false)
+ .build();
+ } else {
+ // No sounds allowed
+ config.setAllowAlarms(false);
+ config.setAllowMedia(false);
+ config.setAllowSystem(false);
+ config.setAllowCalls(false);
+ config.setAllowRepeatCallers(false);
+ config.setAllowMessages(false);
+ config.setAllowReminders(false);
+ config.setAllowEvents(false);
+ config.setAllowConversations(false);
+ config.setAllowConversationsFrom(CONVERSATION_SENDERS_NONE);
+ config.setSuppressedVisualEffects(0);
+ }
+ config.areChannelsBypassingDnd = false;
return config;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
index 2e64645..26a13cb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
@@ -16,6 +16,8 @@
package com.android.server.notification;
+import static android.app.Flags.FLAG_MODES_UI;
+
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
@@ -27,8 +29,10 @@
import android.app.AutomaticZenRule;
import android.app.Flags;
+import android.app.NotificationManager;
import android.content.ComponentName;
import android.net.Uri;
+import android.platform.test.flag.junit.FlagsParameterization;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.service.notification.Condition;
@@ -37,7 +41,6 @@
import android.service.notification.ZenModeDiff;
import android.service.notification.ZenModeDiff.RuleDiff;
import android.service.notification.ZenPolicy;
-import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
@@ -60,8 +63,11 @@
import java.util.Optional;
import java.util.Set;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
@SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(ParameterizedAndroidJunit4.class)
@TestableLooper.RunWithLooper
public class ZenModeDiffTest extends UiServiceTestCase {
// Base set of exempt fields independent of fields that are enabled/disabled via flags.
@@ -91,6 +97,16 @@
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Parameters(name = "{0}")
+ public static List<FlagsParameterization> getParams() {
+ return FlagsParameterization.allCombinationsOf(
+ FLAG_MODES_UI);
+ }
+
+ public ZenModeDiffTest(FlagsParameterization flags) {
+ mSetFlagsRule.setFlagsParameterization(flags);
+ }
+
@Test
public void testRuleDiff_addRemoveSame() {
// Test add, remove, and both sides same
@@ -220,21 +236,35 @@
ZenModeConfig c2 = new ZenModeConfig();
// set c1 and c2 to have some different senders
- c1.allowMessagesFrom = ZenModeConfig.SOURCE_STAR;
- c2.allowMessagesFrom = ZenModeConfig.SOURCE_CONTACT;
- c1.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
- c2.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_NONE;
+ NotificationManager.Policy c1Policy = c1.toNotificationPolicy();
+ c1.applyNotificationPolicy(new NotificationManager.Policy(
+ c1Policy.priorityCategories, c1Policy.priorityCallSenders,
+ c1Policy.PRIORITY_SENDERS_STARRED, c1Policy.suppressedVisualEffects,
+ c1Policy.state, ZenPolicy.CONVERSATION_SENDERS_IMPORTANT));
+
+ NotificationManager.Policy c2Policy = c1.toNotificationPolicy();
+ c2.applyNotificationPolicy(new NotificationManager.Policy(
+ c2Policy.priorityCategories, c2Policy.priorityCallSenders,
+ c2Policy.PRIORITY_SENDERS_CONTACTS, c2Policy.suppressedVisualEffects,
+ c2Policy.state, ZenPolicy.CONVERSATION_SENDERS_NONE));
ZenModeDiff.ConfigDiff d = new ZenModeDiff.ConfigDiff(c1, c2);
assertTrue(d.hasDiff());
- // Diff in top-level fields
- assertTrue(d.getDiffForField("allowMessagesFrom").hasDiff());
- assertTrue(d.getDiffForField("allowConversationsFrom").hasDiff());
+ if (!Flags.modesUi()) {
+ // Diff in top-level fields
+ assertTrue(d.getDiffForField("allowMessagesFrom").hasDiff());
+ assertTrue(d.getDiffForField("allowConversationsFrom").hasDiff());
- // Bonus testing of stringification of people senders and conversation senders
- assertTrue(d.toString().contains("allowMessagesFrom:stars->contacts"));
- assertTrue(d.toString().contains("allowConversationsFrom:important->none"));
+ // Bonus testing of stringification of people senders and conversation senders
+ assertTrue(d.toString().contains("allowMessagesFrom:stars->contacts"));
+ assertTrue(d.toString().contains("allowConversationsFrom:important->none"));
+ } else {
+ RuleDiff r = d.getManualRuleDiff();
+ assertNotNull(r);
+ ZenModeDiff.FieldDiff p = r.getDiffForField(RuleDiff.FIELD_ZEN_POLICY);
+ assertNotNull(p);
+ }
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 72ace84..201b286 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -18,6 +18,8 @@
import static android.app.AutomaticZenRule.TYPE_BEDTIME;
import static android.app.AutomaticZenRule.TYPE_IMMERSIVE;
+import static android.app.Flags.FLAG_MODES_API;
+import static android.app.Flags.FLAG_MODES_UI;
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED;
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DEACTIVATED;
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED;
@@ -41,11 +43,9 @@
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND;
+import static android.app.NotificationManager.Policy.STATE_PRIORITY_CHANNELS_BLOCKED;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
@@ -64,6 +64,11 @@
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_CONTACTS;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_NONE;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_STARRED;
+import static android.service.notification.ZenPolicy.VISUAL_EFFECT_AMBIENT;
+import static android.service.notification.ZenPolicy.VISUAL_EFFECT_BADGE;
+import static android.service.notification.ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT;
+import static android.service.notification.ZenPolicy.VISUAL_EFFECT_LIGHTS;
+import static android.service.notification.ZenPolicy.VISUAL_EFFECT_PEEK;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.LOG_DND_STATE_EVENTS;
import static com.android.os.dnd.DNDProtoEnums.PEOPLE_STARRED;
@@ -75,6 +80,7 @@
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -131,6 +137,7 @@
import android.os.UserHandle;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.provider.Settings.Global;
@@ -140,7 +147,6 @@
import android.service.notification.ZenAdapters;
import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
-import android.service.notification.ZenModeConfig.ConfigChangeOrigin;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.service.notification.ZenModeConfig.ZenRule;
import android.service.notification.ZenModeDiff;
@@ -172,8 +178,6 @@
import com.google.common.truth.Correspondence;
import com.google.common.util.concurrent.SettableFuture;
import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.testing.junit.testparameterinjector.TestParameter;
-import com.google.testing.junit.testparameterinjector.TestParameterInjector;
import org.junit.Before;
import org.junit.Rule;
@@ -202,9 +206,12 @@
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
@SmallTest
@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
-@RunWith(TestParameterInjector.class)
+@RunWith(ParameterizedAndroidJunit4.class)
@TestableLooper.RunWithLooper
public class ZenModeHelperTest extends UiServiceTestCase {
@@ -268,6 +275,16 @@
ZenModeEventLoggerFake mZenModeEventLogger;
private String mPkg;
+ @Parameters(name = "{0}")
+ public static List<FlagsParameterization> getParams() {
+ return FlagsParameterization.progressionOf(FLAG_MODES_API,
+ FLAG_MODES_UI);
+ }
+
+ public ZenModeHelperTest(FlagsParameterization flags) {
+ mSetFlagsRule.setFlagsParameterization(flags);
+ }
+
@Before
public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
@@ -677,7 +694,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testTotalSilence_consolidatedPolicyDisallowsAll() {
// Start with zen mode off just to make sure global/manual mode isn't doing anything.
mZenModeHelper.mZenMode = ZEN_MODE_OFF;
@@ -711,7 +728,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testAlarmsOnly_consolidatedPolicyOnlyAllowsAlarmsAndMedia() {
// Start with zen mode off just to make sure global/manual mode isn't doing anything.
mZenModeHelper.mZenMode = ZEN_MODE_OFF;
@@ -802,15 +819,11 @@
// 1. Current ringer is normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
// Set zen to priority-only with all notification sounds muted (so ringer will be muted)
+ Policy totalSilence = new Policy(0,0,0);
+ mZenModeHelper.setNotificationPolicy(totalSilence, UPDATE_ORIGIN_APP, 1);
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.mConfig.allowReminders = false;
- mZenModeHelper.mConfig.allowCalls = false;
- mZenModeHelper.mConfig.allowMessages = false;
- mZenModeHelper.mConfig.allowEvents = false;
- mZenModeHelper.mConfig.allowRepeatCallers = false;
- mZenModeHelper.mConfig.allowConversations = false;
- // 2. apply priority only zen - verify ringer is unchanged
+ // 2. verify ringer is unchanged
mZenModeHelper.applyZenToRingerMode();
verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT,
mZenModeHelper.TAG);
@@ -844,9 +857,8 @@
public void testRingerAffectedStreamsPriorityOnly() {
// in priority only mode:
// ringtone, notification and system streams are affected by ringer mode
- mZenModeHelper.mConfig.allowAlarms = true;
- mZenModeHelper.mConfig.allowReminders = true;
- mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, Uri.EMPTY,
+ UPDATE_ORIGIN_APP, "test", "caller", 1);
ZenModeHelper.RingerModeDelegate ringerModeDelegateRingerMuted =
mZenModeHelper.new RingerModeDelegate();
@@ -862,13 +874,9 @@
// even when ringer is muted (since all ringer sounds cannot bypass DND),
// system stream is still affected by ringer mode
- mZenModeHelper.mConfig.allowSystem = false;
- mZenModeHelper.mConfig.allowReminders = false;
- mZenModeHelper.mConfig.allowCalls = false;
- mZenModeHelper.mConfig.allowMessages = false;
- mZenModeHelper.mConfig.allowEvents = false;
- mZenModeHelper.mConfig.allowRepeatCallers = false;
- mZenModeHelper.mConfig.allowConversations = false;
+ mZenModeHelper.setNotificationPolicy(new Policy(0,0,0), UPDATE_ORIGIN_APP, 1);
+ mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, Uri.EMPTY,
+ UPDATE_ORIGIN_APP, "test", "caller", 1);
ZenModeHelper.RingerModeDelegate ringerModeDelegateRingerNotMuted =
mZenModeHelper.new RingerModeDelegate();
@@ -885,7 +893,7 @@
}
@Test
- public void testZenSetInternalRinger_NotAllPriorityNotificationSoundsMuted_StartNormal() {
+ public void applyZenToRingerMode_ZEN_MODE_IMPORTANT_INTERRUPTIONS() {
AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class);
mZenModeHelper.mAudioManager = mAudioManager;
Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL,
@@ -894,7 +902,6 @@
// 1. Current ringer is normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.mConfig.allowReminders = true;
// 2. apply priority only zen - verify ringer is normal
mZenModeHelper.applyZenToRingerMode();
@@ -919,7 +926,6 @@
// 1. Current ringer is silent
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.mConfig.allowReminders = true;
// 2. apply priority only zen - verify ringer is silent
mZenModeHelper.applyZenToRingerMode();
@@ -945,7 +951,6 @@
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
// Set zen to priority-only with all notification sounds muted (so ringer will be muted)
mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.mConfig.allowReminders = true;
// 2. apply priority only zen - verify zen will still be normal
mZenModeHelper.applyZenToRingerMode();
@@ -977,11 +982,9 @@
// apply zen off multiple times - verify ringer is not set to normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
- mZenModeHelper.mZenMode = ZEN_MODE_OFF;
- mZenModeHelper.mConfig = null; // will evaluate config to zen mode off
for (int i = 0; i < 3; i++) {
- // if zen doesn't change, zen should not reapply itself to the ringer
- mZenModeHelper.evaluateZenModeLocked(UPDATE_ORIGIN_UNKNOWN, "test", true);
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, Uri.EMPTY,
+ UPDATE_ORIGIN_APP, "test", "caller", 1);
}
verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
mZenModeHelper.TAG);
@@ -991,8 +994,6 @@
public void testSilentRingerSavedOnZenOff_startsZenOn() {
AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class);
mZenModeHelper.mAudioManager = mAudioManager;
- mZenModeHelper.mZenMode = ZEN_MODE_OFF;
- mZenModeHelper.mConfig = new ZenModeConfig();
// previously set silent ringer
ZenModeHelper.RingerModeDelegate ringerModeDelegate =
@@ -1003,12 +1004,12 @@
assertEquals(AudioManager.RINGER_MODE_SILENT, Global.getInt(mContext.getContentResolver(),
Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL));
- // apply zen off multiple times - verify ringer is not set to normal
+ // apply zen on multiple times - verify ringer is not set to normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
- mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
for (int i = 0; i < 3; i++) {
// if zen doesn't change, zen should not reapply itself to the ringer
- mZenModeHelper.evaluateZenModeLocked(UPDATE_ORIGIN_UNKNOWN, "test", true);
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, Uri.EMPTY,
+ UPDATE_ORIGIN_APP, "test", "caller", 1);
}
verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
mZenModeHelper.TAG);
@@ -1018,8 +1019,6 @@
public void testVibrateRingerSavedOnZenOff_startsZenOn() {
AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class);
mZenModeHelper.mAudioManager = mAudioManager;
- mZenModeHelper.mZenMode = ZEN_MODE_OFF;
- mZenModeHelper.mConfig = new ZenModeConfig();
// previously set silent ringer
ZenModeHelper.RingerModeDelegate ringerModeDelegate =
@@ -1032,10 +1031,10 @@
// apply zen off multiple times - verify ringer is not set to normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
- mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
for (int i = 0; i < 3; i++) {
// if zen doesn't change, zen should not reapply itself to the ringer
- mZenModeHelper.evaluateZenModeLocked(UPDATE_ORIGIN_UNKNOWN, "test", true);
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, Uri.EMPTY,
+ UPDATE_ORIGIN_APP, "test", "caller", 1);
}
verify(mAudioManager, never()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
mZenModeHelper.TAG);
@@ -1066,22 +1065,18 @@
@Test
public void testParcelConfig() {
- mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.mConfig.allowAlarms = false;
- mZenModeHelper.mConfig.allowMedia = false;
- mZenModeHelper.mConfig.allowSystem = false;
- mZenModeHelper.mConfig.allowReminders = true;
- mZenModeHelper.mConfig.allowCalls = true;
- mZenModeHelper.mConfig.allowMessages = true;
- mZenModeHelper.mConfig.allowEvents = true;
- mZenModeHelper.mConfig.allowRepeatCallers = true;
- mZenModeHelper.mConfig.allowConversations = true;
- mZenModeHelper.mConfig.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_ANYONE;
- mZenModeHelper.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
- mZenModeHelper.mConfig.manualRule = new ZenModeConfig.ZenRule();
- mZenModeHelper.mConfig.manualRule.component = new ComponentName("a", "a");
- mZenModeHelper.mConfig.manualRule.enabled = true;
- mZenModeHelper.mConfig.manualRule.snoozing = true;
+ mZenModeHelper.setNotificationPolicy(new Policy(PRIORITY_CATEGORY_EVENTS
+ | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_REPEAT_CALLERS
+ | PRIORITY_CATEGORY_CONVERSATIONS, PRIORITY_SENDERS_STARRED,
+ PRIORITY_SENDERS_STARRED, 0, CONVERSATION_SENDERS_ANYONE), UPDATE_ORIGIN_UNKNOWN,
+ 1);
+ mZenModeHelper.setManualZenRuleDeviceEffects(new ZenDeviceEffects.Builder()
+ .setShouldDimWallpaper(true)
+ .setShouldDisplayGrayscale(true)
+ .setShouldUseNightMode(true)
+ .build(), UPDATE_ORIGIN_UNKNOWN, "test", 1);
+ mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, Uri.EMPTY,
+ UPDATE_ORIGIN_UNKNOWN, "test", "me", 1);
ZenModeConfig actual = mZenModeHelper.mConfig.copy();
@@ -1090,24 +1085,17 @@
@Test
public void testWriteXml() throws Exception {
- mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.mConfig.allowAlarms = false;
- mZenModeHelper.mConfig.allowMedia = false;
- mZenModeHelper.mConfig.allowSystem = false;
- mZenModeHelper.mConfig.allowReminders = true;
- mZenModeHelper.mConfig.allowCalls = true;
- mZenModeHelper.mConfig.allowMessages = true;
- mZenModeHelper.mConfig.allowEvents = true;
- mZenModeHelper.mConfig.allowRepeatCallers = true;
- mZenModeHelper.mConfig.allowConversations = true;
- mZenModeHelper.mConfig.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_ANYONE;
- mZenModeHelper.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
- mZenModeHelper.mConfig.manualRule = new ZenModeConfig.ZenRule();
- mZenModeHelper.mConfig.manualRule.zenMode =
- ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- mZenModeHelper.mConfig.manualRule.component = new ComponentName("a", "a");
- mZenModeHelper.mConfig.manualRule.pkg = "a";
- mZenModeHelper.mConfig.manualRule.enabled = true;
+ mZenModeHelper.setNotificationPolicy(new Policy(PRIORITY_CATEGORY_EVENTS
+ | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_REPEAT_CALLERS
+ | PRIORITY_CATEGORY_CONVERSATIONS, PRIORITY_SENDERS_STARRED,
+ PRIORITY_SENDERS_STARRED, SUPPRESSED_EFFECT_BADGE, CONVERSATION_SENDERS_ANYONE),
+ UPDATE_ORIGIN_UNKNOWN, 1);
+ mZenModeHelper.setManualZenRuleDeviceEffects(new ZenDeviceEffects.Builder()
+ .setShouldDimWallpaper(true)
+ .setShouldDisplayGrayscale(true)
+ .build(), UPDATE_ORIGIN_UNKNOWN, "test", 1);
+ mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, Uri.EMPTY,
+ UPDATE_ORIGIN_UNKNOWN, "test", "me", 1);
ZenModeConfig expected = mZenModeHelper.mConfig.copy();
if (Flags.modesUi()) {
@@ -1127,10 +1115,10 @@
@Test
public void testProto() throws InvalidProtocolBufferException {
- mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- // existence of manual rule means it should be in output
- mZenModeHelper.mConfig.manualRule = new ZenModeConfig.ZenRule();
- mZenModeHelper.mConfig.manualRule.pkg = "android"; // system
+ mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null,
+ Flags.modesApi() ? UPDATE_ORIGIN_USER : UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI,
+ null, "test", CUSTOM_PKG_UID);
+
mZenModeHelper.mConfig.automaticRules = new ArrayMap<>(); // no automatic rules
List<String> ids = new ArrayList<>();
@@ -1151,7 +1139,6 @@
assertTrue(cfg.getEnabled());
assertFalse(cfg.getChannelsBypassing());
}
- assertEquals(Process.SYSTEM_UID, cfg.getUid());
String name = cfg.getId();
assertTrue("unexpected rule id", ids.contains(name));
ids.remove(name);
@@ -1255,10 +1242,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testProtoWithAutoRuleCustomPolicy() throws Exception {
- // allowChannels is only valid under modes_api.
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
setupZenConfig();
// clear any automatic rules just to make sure
mZenModeHelper.mConfig.automaticRules = new ArrayMap<>();
@@ -1299,7 +1284,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testProtoWithAutoRuleWithModifiedFields() throws Exception {
setupZenConfig();
mZenModeHelper.mConfig.automaticRules = new ArrayMap<>();
@@ -1384,8 +1369,8 @@
public void testProtoWithManualRule() throws Exception {
setupZenConfig();
mZenModeHelper.mConfig.automaticRules = getCustomAutomaticRules();
- mZenModeHelper.mConfig.manualRule = new ZenModeConfig.ZenRule();
- mZenModeHelper.mConfig.manualRule.enabled = true;
+ mZenModeHelper.setManualZenMode(INTERRUPTION_FILTER_PRIORITY, Uri.EMPTY, UPDATE_ORIGIN_APP,
+ "test", "me", 1);
List<StatsEvent> events = new LinkedList<>();
mZenModeHelper.pullRules(events);
@@ -1408,15 +1393,15 @@
// Setup configs for user 10 and 11.
setupZenConfig();
ZenModeConfig config10 = mZenModeHelper.mConfig.copy();
+ Policy policy = new Policy(PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_ALARMS, 0, 0);
+ config10.applyNotificationPolicy(policy);
config10.user = 10;
- config10.allowAlarms = true;
- config10.allowMedia = true;
mZenModeHelper.setConfig(config10, null, UPDATE_ORIGIN_INIT, "writeXml",
Process.SYSTEM_UID);
ZenModeConfig config11 = mZenModeHelper.mConfig.copy();
config11.user = 11;
- config11.allowAlarms = false;
- config11.allowMedia = false;
+ policy = new Policy(0, 0, 0);
+ config11.applyNotificationPolicy(policy);
mZenModeHelper.setConfig(config11, null, UPDATE_ORIGIN_INIT, "writeXml",
Process.SYSTEM_UID);
@@ -1583,8 +1568,9 @@
}
@Test
- public void testReadXmlRulesNotOverriden() throws Exception {
+ public void testReadXmlRulesNotOverridden() throws Exception {
setupZenConfig();
+ Policy originalPolicy = mZenModeHelper.getNotificationPolicy();
// automatic zen rule is enabled on upgrade so rules should not be overriden to default
ArrayMap<String, ZenModeConfig.ZenRule> enabledAutoRule = new ArrayMap<>();
@@ -1607,7 +1593,7 @@
mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
assertTrue(mZenModeHelper.mConfig.automaticRules.containsKey("customRule"));
- setupZenConfigMaintained();
+ assertEquals(originalPolicy, mZenModeHelper.getNotificationPolicy());
}
@Test
@@ -1626,7 +1612,7 @@
parser.nextTag();
mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
- assertEquals(0, mZenModeHelper.mConfig.suppressedVisualEffects);
+ assertTrue(mZenModeHelper.mConfig.getZenPolicy().shouldShowAllVisualEffects());
xml = "<zen version=\"6\" user=\"0\">\n"
+ "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
@@ -1642,7 +1628,7 @@
parser.nextTag();
mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
- assertEquals(0, mZenModeHelper.mConfig.suppressedVisualEffects);
+ assertTrue(mZenModeHelper.mConfig.getZenPolicy().shouldShowAllVisualEffects());
}
@Test
@@ -1661,7 +1647,7 @@
parser.nextTag();
mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
- assertEquals(0, mZenModeHelper.mConfig.suppressedVisualEffects);
+ assertTrue(mZenModeHelper.mConfig.getZenPolicy().shouldShowAllVisualEffects());
}
@Test
@@ -1680,11 +1666,16 @@
parser.nextTag();
mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
- assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
- | SUPPRESSED_EFFECT_LIGHTS
- | SUPPRESSED_EFFECT_AMBIENT
- | SUPPRESSED_EFFECT_PEEK,
- mZenModeHelper.mConfig.suppressedVisualEffects);
+ assertThat(mZenModeHelper.mConfig.getZenPolicy()
+ .isVisualEffectAllowed(VISUAL_EFFECT_FULL_SCREEN_INTENT, true)).isFalse();
+ assertThat(mZenModeHelper.mConfig.getZenPolicy()
+ .isVisualEffectAllowed(VISUAL_EFFECT_LIGHTS, true)).isFalse();
+ assertThat(mZenModeHelper.mConfig.getZenPolicy()
+ .isVisualEffectAllowed(VISUAL_EFFECT_PEEK, true)).isFalse();
+ assertThat(mZenModeHelper.mConfig.getZenPolicy()
+ .isVisualEffectAllowed(VISUAL_EFFECT_AMBIENT, true)).isFalse();
+ assertThat(mZenModeHelper.mConfig.getZenPolicy()
+ .isVisualEffectAllowed(VISUAL_EFFECT_BADGE, true)).isTrue();
xml = "<zen version=\"6\" user=\"0\">\n"
+ "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
@@ -1700,7 +1691,10 @@
parser.nextTag();
mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
- assertEquals(SUPPRESSED_EFFECT_PEEK, mZenModeHelper.mConfig.suppressedVisualEffects);
+ assertThat(mZenModeHelper.mConfig.getZenPolicy()
+ .isVisualEffectAllowed(VISUAL_EFFECT_PEEK, true)).isFalse();
+ assertThat(mZenModeHelper.mConfig.getZenPolicy()
+ .isVisualEffectAllowed(VISUAL_EFFECT_AMBIENT, true)).isTrue();
xml = "<zen version=\"6\" user=\"0\">\n"
+ "<allow calls=\"false\" repeatCallers=\"false\" messages=\"true\" "
@@ -1716,18 +1710,23 @@
parser.nextTag();
mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
- assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
- | SUPPRESSED_EFFECT_LIGHTS
- | SUPPRESSED_EFFECT_AMBIENT,
- mZenModeHelper.mConfig.suppressedVisualEffects);
+ assertThat(mZenModeHelper.mConfig.getZenPolicy()
+ .isVisualEffectAllowed(VISUAL_EFFECT_FULL_SCREEN_INTENT, true)).isFalse();
+ assertThat(mZenModeHelper.mConfig.getZenPolicy()
+ .isVisualEffectAllowed(VISUAL_EFFECT_LIGHTS, true)).isFalse();
+ assertThat(mZenModeHelper.mConfig.getZenPolicy()
+ .isVisualEffectAllowed(VISUAL_EFFECT_AMBIENT, true)).isFalse();
+ assertThat(mZenModeHelper.mConfig.getZenPolicy()
+ .isVisualEffectAllowed(VISUAL_EFFECT_BADGE, true)).isTrue();
}
@Test
public void testReadXmlResetDefaultRules() throws Exception {
setupZenConfig();
+ Policy originalPolicy = mZenModeHelper.getNotificationPolicy();
// no enabled automatic zen rules and no default rules
- // so rules should be overriden by default rules
+ // so rules should be overridden by default rules
mZenModeHelper.mConfig.automaticRules = new ArrayMap<>();
// set previous version
@@ -1745,13 +1744,14 @@
assertTrue(rules.containsKey(defaultId));
}
- setupZenConfigMaintained();
+ assertEquals(originalPolicy, mZenModeHelper.getNotificationPolicy());
}
@Test
public void testReadXmlAllDisabledRulesResetDefaultRules() throws Exception {
setupZenConfig();
+ Policy originalPolicy = mZenModeHelper.getNotificationPolicy();
// all automatic zen rules are disabled on upgrade (and default rules don't already exist)
// so rules should be overriden by default rules
@@ -1782,12 +1782,13 @@
}
assertFalse(rules.containsKey("customRule"));
- setupZenConfigMaintained();
+ assertEquals(originalPolicy, mZenModeHelper.getNotificationPolicy());
}
@Test
public void testReadXmlOnlyOneDefaultRuleExists() throws Exception {
setupZenConfig();
+ Policy originalPolicy = mZenModeHelper.getNotificationPolicy();
// all automatic zen rules are disabled on upgrade and only one default rule exists
// so rules should be overriden to the default rules
@@ -1834,12 +1835,13 @@
}
assertFalse(rules.containsKey("customRule"));
- setupZenConfigMaintained();
+ assertEquals(originalPolicy, mZenModeHelper.getNotificationPolicy());
}
@Test
public void testReadXmlDefaultRulesExist() throws Exception {
setupZenConfig();
+ Policy originalPolicy = mZenModeHelper.getNotificationPolicy();
// Default rules exist so rules should not be overridden by defaults
ArrayMap<String, ZenModeConfig.ZenRule> automaticRules = new ArrayMap<>();
@@ -1897,13 +1899,13 @@
// check default rules
ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules;
- assertTrue(rules.size() != 0);
+ assertEquals(3, rules.size());
for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) {
assertTrue(rules.containsKey(defaultId));
}
assertTrue(rules.containsKey("customRule"));
- setupZenConfigMaintained();
+ assertEquals(originalPolicy, mZenModeHelper.getNotificationPolicy());
List<StatsEvent> events = new LinkedList<>();
mZenModeHelper.pullRules(events);
@@ -1911,11 +1913,12 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testReadXml_onModesApi_noUpgrade() throws Exception {
// When reading XML for something that is already on the modes API system, make sure no
// rules' policies get changed.
setupZenConfig();
+ Policy originalPolicy = mZenModeHelper.getNotificationPolicy();
// Shared for rules
ArrayMap<String, ZenModeConfig.ZenRule> enabledAutoRules = new ArrayMap<>();
@@ -1947,7 +1950,7 @@
mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
// basic check: global config maintained
- setupZenConfigMaintained();
+ assertEquals(originalPolicy, mZenModeHelper.getNotificationPolicy());
// Find our automatic rules.
ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules;
@@ -1958,12 +1961,13 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testReadXml_upgradeToModesApi_makesCustomPolicies() throws Exception {
// When reading in an XML file written from a pre-modes-API version, confirm that we create
// a custom policy matching the global config for any automatic rule with no specified
// policy.
setupZenConfig();
+ Policy originalPolicy = mZenModeHelper.getNotificationPolicy();
ArrayMap<String, ZenModeConfig.ZenRule> enabledAutoRule = new ArrayMap<>();
ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
@@ -1985,7 +1989,7 @@
mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
// basic check: global config maintained
- setupZenConfigMaintained();
+ assertEquals(originalPolicy, mZenModeHelper.getNotificationPolicy());
// Find our automatic rule and check that it has a policy set now
ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules;
@@ -2009,12 +2013,13 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testReadXml_upgradeToModesApi_fillsInCustomPolicies() throws Exception {
// When reading in an XML file written from a pre-modes-API version, confirm that for an
// underspecified ZenPolicy, we fill in all of the gaps with things from the global config
// in order to maintain consistency of behavior.
setupZenConfig();
+ Policy originalPolicy = mZenModeHelper.getNotificationPolicy();
ArrayMap<String, ZenModeConfig.ZenRule> enabledAutoRule = new ArrayMap<>();
ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
@@ -2041,7 +2046,7 @@
mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
// basic check: global config maintained
- setupZenConfigMaintained();
+ assertEquals(originalPolicy, mZenModeHelper.getNotificationPolicy());
// Find our automatic rule and check that it has a policy set now
ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelper.mConfig.automaticRules;
@@ -2068,7 +2073,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testReadXml_upgradeToModesApi_existingDefaultRulesGetCustomPolicy()
throws Exception {
setupZenConfig();
@@ -2230,7 +2235,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testDefaultRulesFromConfig_modesApi_getPolicies() {
// After mZenModeHelper was created, set some things in the policy so it's changed from
// default.
@@ -2389,7 +2394,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testAddAutomaticZenRule_modesApi_fillsInDefaultValues() {
// When a new automatic zen rule is added with only some fields filled in, ensure that
// all unset fields are filled in with device defaults.
@@ -2436,19 +2441,19 @@
assertThat(rule2InConfig.zenPolicy.getPriorityMessageSenders())
.isEqualTo(PEOPLE_TYPE_CONTACTS);
assertThat(rule2InConfig.zenPolicy.getVisualEffectFullScreenIntent())
- .isEqualTo(ZenPolicy.STATE_ALLOW);
+ .isEqualTo(STATE_ALLOW);
// the rest of rule 2's settings should be the device defaults
assertThat(rule2InConfig.zenPolicy.getPriorityConversationSenders())
.isEqualTo(CONVERSATION_SENDERS_IMPORTANT);
assertThat(rule2InConfig.zenPolicy.getPriorityCategorySystem())
- .isEqualTo(ZenPolicy.STATE_DISALLOW);
+ .isEqualTo(STATE_DISALLOW);
assertThat(rule2InConfig.zenPolicy.getPriorityCategoryAlarms())
- .isEqualTo(ZenPolicy.STATE_ALLOW);
+ .isEqualTo(STATE_ALLOW);
assertThat(rule2InConfig.zenPolicy.getVisualEffectPeek())
- .isEqualTo(ZenPolicy.STATE_DISALLOW);
+ .isEqualTo(STATE_DISALLOW);
assertThat(rule2InConfig.zenPolicy.getVisualEffectNotificationList())
- .isEqualTo(ZenPolicy.STATE_ALLOW);
+ .isEqualTo(STATE_ALLOW);
}
@Test
@@ -2590,9 +2595,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_fromApp_ignoresHiddenEffects() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenDeviceEffects zde = new ZenDeviceEffects.Builder()
.setShouldDisplayGrayscale(true)
.setShouldSuppressAmbientDisplay(true)
@@ -2624,9 +2628,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_fromSystem_respectsHiddenEffects() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenDeviceEffects zde = new ZenDeviceEffects.Builder()
.setShouldDisplayGrayscale(true)
.setShouldSuppressAmbientDisplay(true)
@@ -2652,9 +2655,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_fromUser_respectsHiddenEffects() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
-
ZenDeviceEffects zde = new ZenDeviceEffects.Builder()
.setShouldDisplayGrayscale(true)
.setShouldSuppressAmbientDisplay(true)
@@ -2682,8 +2684,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromApp_preservesPreviousHiddenEffects() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
ZenDeviceEffects original = new ZenDeviceEffects.Builder()
.setShouldDisableTapToWake(true)
.addExtraEffect("extra")
@@ -2717,8 +2719,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromSystem_updatesHiddenEffects() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
ZenDeviceEffects original = new ZenDeviceEffects.Builder()
.setShouldDisableTapToWake(true)
.build();
@@ -2744,8 +2746,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromUser_updatesHiddenEffects() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
ZenDeviceEffects original = new ZenDeviceEffects.Builder()
.setShouldDisableTapToWake(true)
.build();
@@ -2775,7 +2777,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_nullPolicy_doesNothing() {
// Test that when updateAutomaticZenRule is called with a null policy, nothing changes
// about the existing policy.
@@ -2796,11 +2798,11 @@
AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId);
assertThat(savedRule.getZenPolicy().getPriorityCategoryCalls())
- .isEqualTo(ZenPolicy.STATE_DISALLOW);
+ .isEqualTo(STATE_DISALLOW);
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_overwritesExistingPolicy() {
// Test that when updating an automatic zen rule with an existing policy, the newly set
// fields overwrite those from the previous policy, but unset fields in the new policy
@@ -2826,18 +2828,18 @@
AutomaticZenRule savedRule = mZenModeHelper.getAutomaticZenRule(ruleId);
assertThat(savedRule.getZenPolicy().getPriorityCategoryCalls())
- .isEqualTo(ZenPolicy.STATE_ALLOW); // from update
+ .isEqualTo(STATE_ALLOW); // from update
assertThat(savedRule.getZenPolicy().getPriorityCallSenders())
.isEqualTo(ZenPolicy.PEOPLE_TYPE_CONTACTS); // from update
assertThat(savedRule.getZenPolicy().getPriorityCategoryAlarms())
- .isEqualTo(ZenPolicy.STATE_DISALLOW); // from original
+ .isEqualTo(STATE_DISALLOW); // from original
assertThat(savedRule.getZenPolicy().getPriorityCategoryReminders())
- .isEqualTo(ZenPolicy.STATE_ALLOW); // from original
+ .isEqualTo(STATE_ALLOW); // from original
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_withTypeBedtime_replacesDisabledSleeping() {
ZenRule sleepingRule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
@@ -2857,7 +2859,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_withTypeBedtime_keepsEnabledSleeping() {
ZenRule sleepingRule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
@@ -2878,7 +2880,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_withTypeBedtime_keepsCustomizedSleeping() {
ZenRule sleepingRule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
@@ -2899,8 +2901,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testSetManualZenMode() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
setupZenConfig();
// note that caller=null because that's how it comes in from NMS.setZenMode
@@ -2919,68 +2921,83 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
- @DisableFlags(Flags.FLAG_MODES_UI)
- public void setManualZenMode_off_snoozesActiveRules(@TestParameter ChangeOrigin setZenOrigin) {
- // Start with an active rule and an inactive rule.
- mZenModeHelper.mConfig.automaticRules.clear();
- AutomaticZenRule activeRule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .build();
- String activeRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
- activeRule, UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
- mZenModeHelper.setAutomaticZenRuleState(activeRuleId, CONDITION_TRUE, UPDATE_ORIGIN_APP,
- CUSTOM_PKG_UID);
- AutomaticZenRule inactiveRule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .build();
- String inactiveRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
- inactiveRule, UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+ @EnableFlags(FLAG_MODES_API)
+ @DisableFlags(FLAG_MODES_UI)
+ public void setManualZenMode_off_snoozesActiveRules() {
+ for (ChangeOrigin origin : ChangeOrigin.values()) {
+ // Start with an active rule and an inactive rule.
+ mZenModeHelper.mConfig.automaticRules.clear();
+ AutomaticZenRule activeRule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .build();
+ String activeRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ activeRule, UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+ mZenModeHelper.setAutomaticZenRuleState(activeRuleId, CONDITION_TRUE, UPDATE_ORIGIN_APP,
+ CUSTOM_PKG_UID);
+ AutomaticZenRule inactiveRule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .build();
+ String inactiveRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ inactiveRule, UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
- assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ assertWithMessage("Failure for origin " + origin.name())
+ .that(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- // User turns DND off.
- mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null, setZenOrigin.value(),
- "snoozing", "systemui", Process.SYSTEM_UID);
- assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
- assertThat(mZenModeHelper.mConfig.automaticRules.get(activeRuleId).snoozing).isTrue();
- assertThat(mZenModeHelper.mConfig.automaticRules.get(inactiveRuleId).snoozing).isFalse();
+ // User turns DND off.
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null, origin.value(),
+ "snoozing", "systemui", Process.SYSTEM_UID);
+ assertWithMessage("Failure for origin " + origin.name())
+ .that(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+ assertWithMessage("Failure for origin " + origin.name())
+ .that(mZenModeHelper.mConfig.automaticRules.get(activeRuleId).snoozing)
+ .isTrue();
+ assertWithMessage("Failure for origin " + origin.name())
+ .that(mZenModeHelper.mConfig.automaticRules.get(inactiveRuleId).snoozing)
+ .isFalse();
+ }
}
@Test
- @EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
- public void setManualZenMode_off_doesNotSnoozeRulesIfFromUser(
- @TestParameter ChangeOrigin setZenOrigin) {
- // Start with an active rule and an inactive rule
- mZenModeHelper.mConfig.automaticRules.clear();
- AutomaticZenRule activeRule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .build();
- String activeRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
- activeRule, UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
- mZenModeHelper.setAutomaticZenRuleState(activeRuleId, CONDITION_TRUE, UPDATE_ORIGIN_APP,
- CUSTOM_PKG_UID);
- AutomaticZenRule inactiveRule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .build();
- String inactiveRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
- inactiveRule, UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+ @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ public void setManualZenMode_off_doesNotSnoozeRulesIfFromUser() {
+ for (ChangeOrigin origin : ChangeOrigin.values()) {
+ // Start with an active rule and an inactive rule
+ mZenModeHelper.mConfig.automaticRules.clear();
+ AutomaticZenRule activeRule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .build();
+ String activeRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ activeRule, UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+ mZenModeHelper.setAutomaticZenRuleState(activeRuleId, CONDITION_TRUE, UPDATE_ORIGIN_APP,
+ CUSTOM_PKG_UID);
+ AutomaticZenRule inactiveRule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .build();
+ String inactiveRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ inactiveRule, UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
- assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
-
- // User turns DND off.
- mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null, setZenOrigin.value(),
- "snoozing", "systemui", Process.SYSTEM_UID);
- ZenModeConfig config = mZenModeHelper.mConfig;
- if (setZenOrigin == ChangeOrigin.ORIGIN_USER) {
- // Other rule was unaffected.
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- assertThat(config.automaticRules.get(activeRuleId).snoozing).isFalse();
- assertThat(config.automaticRules.get(inactiveRuleId).snoozing).isFalse();
- } else {
- assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
- assertThat(config.automaticRules.get(activeRuleId).snoozing).isTrue();
- assertThat(config.automaticRules.get(inactiveRuleId).snoozing).isFalse();
+
+ // User turns DND off.
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null, origin.value(),
+ "snoozing", "systemui", Process.SYSTEM_UID);
+ ZenModeConfig config = mZenModeHelper.mConfig;
+ if (origin == ChangeOrigin.ORIGIN_USER) {
+ // Other rule was unaffected.
+ assertWithMessage("Failure for origin " + origin.name()).that(
+ mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ assertWithMessage("Failure for origin " + origin.name()).that(
+ config.automaticRules.get(activeRuleId).snoozing).isFalse();
+ assertWithMessage("Failure for origin " + origin.name()).that(
+ config.automaticRules.get(inactiveRuleId).snoozing).isFalse();
+ } else {
+ assertWithMessage("Failure for origin " + origin.name()).that(
+ mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+ assertWithMessage("Failure for origin " + origin.name()).that(
+ config.automaticRules.get(activeRuleId).snoozing).isTrue();
+ assertWithMessage("Failure for origin " + origin.name()).that(
+ config.automaticRules.get(inactiveRuleId).snoozing).isFalse();
+ }
}
}
@@ -3002,45 +3019,17 @@
assertEquals(ZEN_MODE_OFF, mZenModeHelper.mZenMode);
}
- private enum ModesFlag {
- MODES_UI(2, /* originForUserActionInSystemUi= */ UPDATE_ORIGIN_USER),
- MODES_API(1, /* originForUserActionInSystemUi= */ UPDATE_ORIGIN_USER),
- DISABLED(0, /* originForUserActionInSystemUi= */ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI);
-
- private final int mFlagsEnabled;
- @ConfigChangeOrigin
- private final int mOriginForUserActionInSystemUi;
-
- ModesFlag(int flagsEnabled, @ConfigChangeOrigin int originForUserActionInSystemUi) {
- this.mFlagsEnabled = flagsEnabled;
- this.mOriginForUserActionInSystemUi = originForUserActionInSystemUi;
- }
-
- void applyFlags(SetFlagsRule setFlagsRule) {
- if (mFlagsEnabled >= 1) {
- setFlagsRule.enableFlags(Flags.FLAG_MODES_API);
- } else {
- setFlagsRule.disableFlags(Flags.FLAG_MODES_API);
- }
- if (mFlagsEnabled >= 2) {
- setFlagsRule.enableFlags(Flags.FLAG_MODES_UI);
- } else {
- setFlagsRule.disableFlags(Flags.FLAG_MODES_UI);
- }
- }
- }
-
@Test
- public void testZenModeEventLog_setManualZenMode(@TestParameter ModesFlag modesFlag)
+ public void testZenModeEventLog_setManualZenMode()
throws IllegalArgumentException {
- modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
// Turn zen mode on (to important_interruptions)
// Need to additionally call the looper in order to finish the post-apply-config process
mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null,
- modesFlag.mOriginForUserActionInSystemUi, "", null, Process.SYSTEM_UID);
+ Flags.modesApi() ? UPDATE_ORIGIN_USER: UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "", null,
+ Process.SYSTEM_UID);
// Now turn zen mode off, but via a different package UID -- this should get registered as
// "not an action by the user" because some other app is changing zen mode
@@ -3068,7 +3057,7 @@
assertEquals(DNDProtoEnums.MANUAL_RULE, mZenModeEventLogger.getChangedRuleType(0));
assertEquals(1, mZenModeEventLogger.getNumRulesActive(0));
assertThat(mZenModeEventLogger.getFromSystemOrSystemUi(0)).isEqualTo(
- modesFlag == ModesFlag.DISABLED);
+ !(Flags.modesUi() || Flags.modesApi()));
assertTrue(mZenModeEventLogger.getIsUserAction(0));
assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(0));
checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(0));
@@ -3097,9 +3086,8 @@
}
@Test
- public void testZenModeEventLog_automaticRules(@TestParameter ModesFlag modesFlag)
+ public void testZenModeEventLog_automaticRules()
throws IllegalArgumentException {
- modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3116,15 +3104,14 @@
// Event 1: Mimic the rule coming on automatically by setting the Condition to STATE_TRUE
mZenModeHelper.setAutomaticZenRuleState(id,
new Condition(zenRule.getConditionId(), "", STATE_TRUE),
- UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI,
- Process.SYSTEM_UID);
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
// Event 2: "User" turns off the automatic rule (sets it to not enabled)
zenRule.setEnabled(false);
mZenModeHelper.updateAutomaticZenRule(id, zenRule,
- modesFlag.mOriginForUserActionInSystemUi, "", Process.SYSTEM_UID);
+ Flags.modesApi() ? UPDATE_ORIGIN_USER: UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "",
+ Process.SYSTEM_UID);
- // Add a new system rule
AutomaticZenRule systemRule = new AutomaticZenRule("systemRule",
null,
new ComponentName("android", "ScheduleConditionProvider"),
@@ -3132,7 +3119,8 @@
null,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String systemId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), systemRule,
- UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test", Process.SYSTEM_UID);
+ Flags.modesApi() ? UPDATE_ORIGIN_USER: UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test",
+ Process.SYSTEM_UID);
// Event 3: turn on the system rule
mZenModeHelper.setAutomaticZenRuleState(systemId,
@@ -3140,9 +3128,9 @@
UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
// Event 4: "User" deletes the rule
- mZenModeHelper.removeAutomaticZenRule(systemId, modesFlag.mOriginForUserActionInSystemUi,
- "", Process.SYSTEM_UID);
-
+ mZenModeHelper.removeAutomaticZenRule(systemId,
+ Flags.modesApi() ? UPDATE_ORIGIN_USER: UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "",
+ Process.SYSTEM_UID);
// In total, this represents 4 events
assertEquals(4, mZenModeEventLogger.numLoggedChanges());
@@ -3201,7 +3189,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testZenModeEventLog_automaticRuleActivatedFromAppByAppAndUser()
throws IllegalArgumentException {
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
@@ -3288,22 +3276,19 @@
}
@Test
- public void testZenModeEventLog_policyChanges(@TestParameter ModesFlag modesFlag)
+ public void testZenModeEventLog_policyChanges()
throws IllegalArgumentException {
- modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
// First just turn zen mode on
mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null,
- modesFlag.mOriginForUserActionInSystemUi, "", null, Process.SYSTEM_UID);
+ UPDATE_ORIGIN_USER, "", null, Process.SYSTEM_UID);
// Now change the policy slightly; want to confirm that this'll be reflected in the logs
ZenModeConfig newConfig = mZenModeHelper.mConfig.copy();
- newConfig.allowAlarms = true;
- newConfig.allowRepeatCallers = false;
- mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(),
- modesFlag.mOriginForUserActionInSystemUi, Process.SYSTEM_UID);
+ mZenModeHelper.setNotificationPolicy(new Policy(PRIORITY_CATEGORY_ALARMS, 0, 0),
+ UPDATE_ORIGIN_USER, Process.SYSTEM_UID);
// Turn zen mode off; we want to make sure policy changes do not get logged when zen mode
// is off.
@@ -3311,10 +3296,8 @@
null, Process.SYSTEM_UID);
// Change the policy again
- newConfig.allowMessages = false;
- newConfig.allowRepeatCallers = true;
- mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(),
- modesFlag.mOriginForUserActionInSystemUi, Process.SYSTEM_UID);
+ mZenModeHelper.setNotificationPolicy(new Policy(PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0),
+ UPDATE_ORIGIN_USER, Process.SYSTEM_UID);
// Total events: we only expect ones for turning on, changing policy, and turning off
assertEquals(3, mZenModeEventLogger.numLoggedChanges());
@@ -3347,9 +3330,7 @@
}
@Test
- public void testZenModeEventLog_ruleCounts(@TestParameter ModesFlag modesFlag)
- throws IllegalArgumentException {
- modesFlag.applyFlags(mSetFlagsRule);
+ public void testZenModeEventLog_ruleCounts() throws IllegalArgumentException {
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3374,14 +3355,12 @@
// Rule 3, has stricter settings than the default settings
ZenModeConfig ruleConfig = mZenModeHelper.mConfig.copy();
- ruleConfig.allowReminders = false;
- ruleConfig.allowCalls = false;
- ruleConfig.allowMessages = false;
+ ruleConfig.applyNotificationPolicy(new Policy(0, 0, 0));
AutomaticZenRule zenRule3 = new AutomaticZenRule("name3",
null,
new ComponentName("android", "ScheduleConditionProvider"),
ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
- ruleConfig.toZenPolicy(),
+ ruleConfig.getZenPolicy(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id3 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule3,
UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "test", Process.SYSTEM_UID);
@@ -3452,10 +3431,8 @@
}
@Test
- public void testZenModeEventLog_noLogWithNoConfigChange(
- @TestParameter ModesFlag modesFlag) throws IllegalArgumentException {
+ public void testZenModeEventLog_noLogWithNoConfigChange() throws IllegalArgumentException {
// If evaluateZenMode is called independently of a config change, don't log.
- modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3472,17 +3449,16 @@
}
@Test
- public void testZenModeEventLog_reassignUid(@TestParameter ModesFlag modesFlag)
+ public void testZenModeEventLog_reassignUid()
throws IllegalArgumentException {
// Test that, only in specific cases, we reassign the calling UID to one associated with
// the automatic rule owner.
- modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
// Explicitly set up all rules with the same policy as the manual rule so there will be
// no policy changes in this test case.
- ZenPolicy manualRulePolicy = mZenModeHelper.mConfig.toZenPolicy();
+ ZenPolicy manualRulePolicy = mZenModeHelper.mConfig.getZenPolicy();
// Rule 1, owned by a package
AutomaticZenRule zenRule = new AutomaticZenRule("name",
@@ -3502,7 +3478,7 @@
manualRulePolicy,
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
String id2 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule2,
- modesFlag.mOriginForUserActionInSystemUi, "test", Process.SYSTEM_UID);
+ UPDATE_ORIGIN_USER, "test", Process.SYSTEM_UID);
// Turn on rule 1; call looks like it's from the system. Because setting a condition is
// typically an automatic (non-user-initiated) action, expect the calling UID to be
@@ -3521,7 +3497,7 @@
// from the system-provided one.
zenRule.setEnabled(false);
mZenModeHelper.updateAutomaticZenRule(id, zenRule,
- modesFlag.mOriginForUserActionInSystemUi, "", Process.SYSTEM_UID);
+ UPDATE_ORIGIN_USER, "", Process.SYSTEM_UID);
// Add a manual rule. Any manual rule changes should not get calling uids reassigned.
mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, UPDATE_ORIGIN_APP,
@@ -3578,10 +3554,8 @@
}
@Test
- public void testZenModeEventLog_channelsBypassingChanges(
- @TestParameter ModesFlag modesFlag) {
+ public void testZenModeEventLog_channelsBypassingChanges() {
// Verify that the right thing happens when the canBypassDnd value changes.
- modesFlag.applyFlags(mSetFlagsRule);
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3589,21 +3563,25 @@
// as a user action, and *should* get its UID reassigned.
mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null,
UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "", CUSTOM_PKG_NAME, Process.SYSTEM_UID);
+ assertEquals(1, mZenModeEventLogger.numLoggedChanges());
// Now change apps bypassing to true
ZenModeConfig newConfig = mZenModeHelper.mConfig.copy();
newConfig.areChannelsBypassingDnd = true;
mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(),
UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+ assertEquals(2, mZenModeEventLogger.numLoggedChanges());
// and then back to false, all without changing anything else
newConfig.areChannelsBypassingDnd = false;
mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(),
UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+ assertEquals(3, mZenModeEventLogger.numLoggedChanges());
// Turn off manual mode, call from a package: don't reset UID even though enabler is set
mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null, UPDATE_ORIGIN_APP, "",
CUSTOM_PKG_NAME, 12345);
+ assertEquals(4, mZenModeEventLogger.numLoggedChanges());
// And likewise when turning it back on again
mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, UPDATE_ORIGIN_APP,
@@ -3642,11 +3620,11 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testZenModeEventLog_policyAllowChannels() {
// when modes_api flag is on, ensure that any change in allow_channels gets logged,
// even when there are no other changes.
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
// Default zen config has allow channels = priority (aka on)
setupZenConfig();
@@ -3658,8 +3636,12 @@
// Now change only the channels part of the policy; want to confirm that this'll be
// reflected in the logs
ZenModeConfig newConfig = mZenModeHelper.mConfig.copy();
- newConfig.allowPriorityChannels = false;
- mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(),
+ Policy oldPolicy = newConfig.toNotificationPolicy();
+ Policy newPolicy = new Policy(oldPolicy.priorityCategories, oldPolicy.priorityCallSenders,
+ oldPolicy.priorityMessageSenders, oldPolicy.suppressedVisualEffects,
+ STATE_PRIORITY_CHANNELS_BLOCKED,
+ oldPolicy.priorityConversationSenders);
+ mZenModeHelper.setNotificationPolicy(newPolicy,
UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
// Total events: one for turning on, one for changing policy
@@ -3688,7 +3670,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testZenModeEventLog_ruleWithInterruptionFilterAll_notLoggedAsDndChange() {
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3730,7 +3712,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testZenModeEventLog_activeRuleTypes() {
mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true);
setupZenConfig();
@@ -3748,7 +3730,7 @@
// Create immersive rule
AutomaticZenRule immersive = new AutomaticZenRule.Builder("Immersed", CONDITION_ID)
.setType(TYPE_IMMERSIVE)
- .setZenPolicy(mZenModeHelper.mConfig.toZenPolicy()) // same as the manual rule
+ .setZenPolicy(mZenModeHelper.mConfig.getZenPolicy()) // same as the manual rule
.build();
String immersiveId = mZenModeHelper.addAutomaticZenRule(mPkg, immersive, UPDATE_ORIGIN_APP,
"reason", CUSTOM_PKG_UID);
@@ -3819,10 +3801,9 @@
}
@Test
- @DisableFlags(Flags.FLAG_MODES_API)
+ @DisableFlags(FLAG_MODES_API)
public void testUpdateConsolidatedPolicy_preModesApiDefaultRulesOnly_takesGlobalDefault() {
setupZenConfig();
-
// When there's one automatic rule active and it doesn't specify a policy, test that the
// resulting consolidated policy is one that matches the default rule settings.
AutomaticZenRule zenRule = new AutomaticZenRule("name",
@@ -3839,6 +3820,9 @@
new Condition(zenRule.getConditionId(), "", STATE_TRUE),
UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, Process.SYSTEM_UID);
+ assertEquals(mZenModeHelper.getNotificationPolicy(),
+ mZenModeHelper.getConsolidatedNotificationPolicy());
+
// inspect the consolidated policy. Based on setupZenConfig() values.
assertFalse(mZenModeHelper.mConsolidatedPolicy.allowAlarms());
assertFalse(mZenModeHelper.mConsolidatedPolicy.allowMedia());
@@ -3853,9 +3837,7 @@
}
@Test
- public void testUpdateConsolidatedPolicy_modesApiDefaultRulesOnly_takesDefault(
- @TestParameter({"MODES_UI", "MODES_API"}) ModesFlag modesFlag) {
- modesFlag.applyFlags(mSetFlagsRule);
+ public void testUpdateConsolidatedPolicy_modesApiDefaultRulesOnly_takesDefault() {
setupZenConfig();
// When there's one automatic rule active and it doesn't specify a policy, test that the
@@ -3876,13 +3858,13 @@
// inspect the consolidated policy, which should match the device default settings.
assertThat(ZenAdapters.notificationPolicyToZenPolicy(mZenModeHelper.mConsolidatedPolicy))
- .isEqualTo(modesFlag == ModesFlag.MODES_UI
+ .isEqualTo(Flags.modesUi()
? mZenModeHelper.getDefaultZenPolicy()
- : mZenModeHelper.mConfig.toZenPolicy());
+ : mZenModeHelper.mConfig.getZenPolicy());
}
@Test
- @DisableFlags(Flags.FLAG_MODES_API)
+ @DisableFlags(FLAG_MODES_API)
public void testUpdateConsolidatedPolicy_preModesApiCustomPolicyOnly_fillInWithGlobal() {
setupZenConfig();
@@ -3928,9 +3910,8 @@
}
@Test
- public void testUpdateConsolidatedPolicy_modesApiCustomPolicyOnly_fillInWithDefault(
- @TestParameter({"MODES_UI", "MODES_API"}) ModesFlag modesFlag) {
- modesFlag.applyFlags(mSetFlagsRule);
+ @EnableFlags(FLAG_MODES_API)
+ public void testUpdateConsolidatedPolicy_modesApiCustomPolicyOnly_fillInWithDefault() {
setupZenConfig();
// when there's only one automatic rule active and it has a custom policy, make sure that's
@@ -3962,12 +3943,12 @@
// policy for every field specified, and take default values (from either device default
// policy or manual rule) for unspecified things
assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isEqualTo(
- modesFlag == ModesFlag.MODES_UI ? true : false); // default
+ Flags.modesUi() ? true : false); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isEqualTo(
- modesFlag == ModesFlag.MODES_UI ? true : false); // default
+ Flags.modesUi() ? true : false); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isTrue(); // custom
assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isEqualTo(
- modesFlag == ModesFlag.MODES_UI ? false : true); // default
+ Flags.modesUi() ? false : true); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowCalls()).isFalse(); // custom
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMessages()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers()).isFalse(); // custom
@@ -3976,7 +3957,7 @@
}
@Test
- @DisableFlags(Flags.FLAG_MODES_API)
+ @DisableFlags(FLAG_MODES_API)
public void testUpdateConsolidatedPolicy_preModesApiDefaultAndCustomActive_mergesWithGlobal() {
setupZenConfig();
@@ -4037,9 +4018,8 @@
}
@Test
- public void testUpdateConsolidatedPolicy_modesApiDefaultAndCustomActive_mergesWithDefault(
- @TestParameter({"MODES_UI", "MODES_API"}) ModesFlag modesFlag) {
- modesFlag.applyFlags(mSetFlagsRule);
+ @EnableFlags(FLAG_MODES_API)
+ public void testUpdateConsolidatedPolicy_modesApiDefaultAndCustomActive_mergesWithDefault() {
setupZenConfig();
// when there are two rules active, one inheriting the default policy and one setting its
@@ -4088,10 +4068,10 @@
// restrictive option of each of the two
assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isFalse(); // custom stricter
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isEqualTo(
- modesFlag == ModesFlag.MODES_UI ? true : false); // default
+ Flags.modesUi() ? true : false); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isFalse(); // default stricter
assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isEqualTo(
- modesFlag == ModesFlag.MODES_UI ? false : true); // default
+ Flags.modesUi() ? false : true); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowCalls()).isFalse(); // custom stricter
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMessages()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowConversations()).isTrue(); // default
@@ -4099,12 +4079,12 @@
.isFalse(); // custom stricter
assertThat(mZenModeHelper.mConsolidatedPolicy.showBadges()).isFalse(); // custom stricter
assertThat(mZenModeHelper.mConsolidatedPolicy.showPeeking()).isEqualTo(
- modesFlag == ModesFlag.MODES_UI ? false : true); // default
+ Flags.modesUi() ? false : true); // default
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testUpdateConsolidatedPolicy_allowChannels() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
setupZenConfig();
// one rule, custom policy, allows channels
@@ -4153,9 +4133,8 @@
}
@Test
- public void testUpdateConsolidatedPolicy_ignoresActiveRulesWithInterruptionFilterAll(
- @TestParameter({"MODES_UI", "MODES_API"}) ModesFlag modesFlag) {
- modesFlag.applyFlags(mSetFlagsRule);
+ @EnableFlags(FLAG_MODES_API)
+ public void testUpdateConsolidatedPolicy_ignoresActiveRulesWithInterruptionFilterAll() {
setupZenConfig();
// Rules with INTERRUPTION_FILTER_ALL are skipped when calculating consolidated policy.
@@ -4193,11 +4172,11 @@
// Consolidated Policy should be default + rule1.
assertThat(mZenModeHelper.mConsolidatedPolicy.allowAlarms()).isEqualTo(
- modesFlag == ModesFlag.MODES_UI ? true : false); // default
+ Flags.modesUi() ? true : false); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMedia()).isTrue(); // priority rule
assertThat(mZenModeHelper.mConsolidatedPolicy.allowSystem()).isTrue(); // priority rule
assertThat(mZenModeHelper.mConsolidatedPolicy.allowReminders()).isEqualTo(
- modesFlag == ModesFlag.MODES_UI ? false : true); // default
+ Flags.modesUi() ? false : true); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowCalls()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowMessages()).isTrue(); // default
assertThat(mZenModeHelper.mConsolidatedPolicy.allowConversations()).isTrue(); // default
@@ -4205,8 +4184,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void zenRuleToAutomaticZenRule_allFields() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
new String[]{OWNER.getPackageName()});
@@ -4249,8 +4228,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void automaticZenRuleToZenRule_allFields() {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
new String[]{OWNER.getPackageName()});
@@ -4291,7 +4270,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromApp_updatesNameUnlessUserModified() {
// Add a starting rule with the name OriginalName.
AutomaticZenRule azrBase = new AutomaticZenRule.Builder("OriginalName", CONDITION_ID)
@@ -4348,7 +4327,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromUser_updatesBitmaskAndValue() {
// Adds a starting rule with empty zen policies and device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4385,7 +4364,7 @@
assertThat(rule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_PRIORITY);
assertThat(rule.getIconResId()).isEqualTo(ICON_RES_ID);
assertThat(rule.getZenPolicy().getPriorityChannelsAllowed()).isEqualTo(
- ZenPolicy.STATE_DISALLOW);
+ STATE_DISALLOW);
assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue();
@@ -4401,7 +4380,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromSystemUi_updatesValues() {
// Adds a starting rule with empty zen policies and device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4441,7 +4420,7 @@
// UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI should change the value but NOT update the bitmask.
assertThat(rule.getIconResId()).isEqualTo(ICON_RES_ID);
assertThat(rule.getZenPolicy().getPriorityCategoryReminders())
- .isEqualTo(ZenPolicy.STATE_ALLOW);
+ .isEqualTo(STATE_ALLOW);
assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue();
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
@@ -4451,7 +4430,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_fromApp_updatesValuesIfRuleNotUserModified() {
// Adds a starting rule with empty zen policies and device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4490,7 +4469,7 @@
assertThat(storedRule.zenMode).isEqualTo(ZEN_MODE_ALARMS);
assertThat(storedRule.zenPolicy.getPriorityCategoryReminders())
- .isEqualTo(ZenPolicy.STATE_ALLOW);
+ .isEqualTo(STATE_ALLOW);
assertThat(storedRule.zenDeviceEffects.shouldDisplayGrayscale()).isTrue();
assertThat(storedRule.userModifiedFields).isEqualTo(0);
assertThat(storedRule.zenPolicyUserModifiedFields).isEqualTo(0);
@@ -4514,7 +4493,7 @@
// so the rule is not changed, and neither is the bitmask.
assertThat(ruleUser.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALL);
assertThat(ruleUser.getZenPolicy().getPriorityCategoryReminders())
- .isEqualTo(ZenPolicy.STATE_DISALLOW);
+ .isEqualTo(STATE_DISALLOW);
assertThat(ruleUser.getDeviceEffects().shouldDisplayGrayscale()).isFalse();
storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleIdUser);
@@ -4525,7 +4504,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_updatesValues() {
// Adds a starting rule with empty zen policies and device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4543,7 +4522,7 @@
// The values are modified but the bitmask is not.
assertThat(rule.getZenPolicy().getPriorityCategoryReminders())
- .isEqualTo(ZenPolicy.STATE_ALLOW);
+ .isEqualTo(STATE_ALLOW);
assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue();
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
@@ -4551,7 +4530,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_nullDeviceEffectsUpdate() {
// Adds a starting rule with empty zen policies and device effects
ZenDeviceEffects zde = new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build();
@@ -4578,7 +4557,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_nullPolicyUpdate() {
// Adds a starting rule with set zen policy and empty device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4607,7 +4586,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void automaticZenRuleToZenRule_nullToNonNullPolicyUpdate() {
when(mContext.checkCallingPermission(anyString()))
.thenReturn(PackageManager.PERMISSION_GRANTED);
@@ -4654,7 +4633,7 @@
// New ZenPolicy differs from the default config
assertThat(rule.getZenPolicy()).isNotNull();
assertThat(rule.getZenPolicy().getPriorityChannelsAllowed()).isEqualTo(
- ZenPolicy.STATE_DISALLOW);
+ STATE_DISALLOW);
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
assertThat(storedRule.canBeUpdatedByApp()).isFalse();
@@ -4671,7 +4650,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void automaticZenRuleToZenRule_nullToNonNullDeviceEffectsUpdate() {
// Adds a starting rule with empty zen policies and device effects
AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
@@ -4775,8 +4754,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testUpdateAutomaticRule_activated_triggersBroadcast() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
setupZenConfig();
// Add a new automatic zen rule that's enabled
@@ -4815,8 +4794,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testUpdateAutomaticRule_deactivatedByUser_triggersBroadcast() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
setupZenConfig();
// Add a new automatic zen rule that's enabled
@@ -4860,8 +4839,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testUpdateAutomaticRule_deactivatedByApp_triggersBroadcast() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
setupZenConfig();
// Add a new automatic zen rule that's enabled
@@ -4937,7 +4916,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_ruleChanged_deactivatesRule() {
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", CONDITION_ID)
@@ -4961,7 +4940,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void updateAutomaticZenRule_ruleNotChanged_doesNotDeactivateRule() {
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", CONDITION_ID)
@@ -4984,7 +4963,7 @@
}
@Test
- @EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
public void updateAutomaticZenRule_ruleChangedByUser_doesNotDeactivateRule() {
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", CONDITION_ID)
@@ -5009,7 +4988,7 @@
}
@Test
- @EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
public void updateAutomaticZenRule_ruleDisabledByUser_doesNotReactivateOnReenable() {
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", CONDITION_ID)
@@ -5034,7 +5013,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void removeAutomaticZenRule_propagatesOriginToEffectsApplier() {
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
reset(mDeviceEffectsApplier);
@@ -5057,8 +5036,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_applied() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
verify(mDeviceEffectsApplier).apply(eq(NO_EFFECTS), eq(UPDATE_ORIGIN_INIT));
@@ -5077,8 +5056,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_onDeactivateRule_applied() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
ZenDeviceEffects zde = new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build();
@@ -5096,8 +5075,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_changeToConsolidatedEffects_applied() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
verify(mDeviceEffectsApplier).apply(eq(NO_EFFECTS), eq(UPDATE_ORIGIN_INIT));
@@ -5136,8 +5115,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_noChangeToConsolidatedEffects_notApplied() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
verify(mDeviceEffectsApplier).apply(eq(NO_EFFECTS), eq(UPDATE_ORIGIN_INIT));
@@ -5161,9 +5140,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_activeBeforeApplierProvided_appliedWhenProvided() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
ZenDeviceEffects zde = new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build();
String ruleId = addRuleWithEffects(zde);
verify(mDeviceEffectsApplier, never()).apply(any(), anyInt());
@@ -5178,8 +5156,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testDeviceEffects_onUserSwitch_appliedImmediately() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
verify(mDeviceEffectsApplier).apply(eq(NO_EFFECTS), eq(UPDATE_ORIGIN_INIT));
@@ -5214,9 +5192,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_wasCustomized_isRestored() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
// Start with a rule.
mZenModeHelper.mConfig.automaticRules.clear();
mTestClock.setNowMillis(1000);
@@ -5257,7 +5234,7 @@
assertThat(newRuleId).isEqualTo(ruleId);
assertThat(finalRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALARMS);
assertThat(finalRule.getZenPolicy().getPriorityCategoryRepeatCallers()).isEqualTo(
- ZenPolicy.STATE_ALLOW);
+ STATE_ALLOW);
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
assertThat(storedRule.userModifiedFields).isEqualTo(
@@ -5270,9 +5247,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_wasNotCustomized_isNotRestored() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
// Start with a single rule.
mZenModeHelper.mConfig.automaticRules.clear();
mTestClock.setNowMillis(1000);
@@ -5303,9 +5279,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_recreatedButNotByApp_isNotRestored() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
// Start with a single rule.
mZenModeHelper.mConfig.automaticRules.clear();
mTestClock.setNowMillis(1000);
@@ -5345,16 +5320,15 @@
assertThat(newRuleId).isNotEqualTo(ruleId);
assertThat(finalRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_PRIORITY);
assertThat(finalRule.getZenPolicy().getPriorityCategoryRepeatCallers()).isEqualTo(
- ZenPolicy.STATE_DISALLOW);
+ STATE_DISALLOW);
// Also, we discarded the "deleted rule" since we're not interested in recreating it.
assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(0);
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_removedByUser_isNotRestored() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
// Start with a single rule.
mZenModeHelper.mConfig.automaticRules.clear();
mTestClock.setNowMillis(1000);
@@ -5394,8 +5368,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void removeAutomaticZenRule_preservedForRestoringByPackageAndConditionId() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS,
PERMISSION_GRANTED); // So that canManageAZR passes although packages don't match.
mZenModeHelper.mConfig.automaticRules.clear();
@@ -5434,8 +5408,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void removeAllZenRules_preservedForRestoring() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
@@ -5456,8 +5430,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void removeAllZenRules_fromSystem_deletesPreservedRulesToo() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
// Start with deleted rules from 2 different packages.
@@ -5476,7 +5450,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_wasActive_isRestoredAsInactive() {
// Start with a rule.
mZenModeHelper.mConfig.automaticRules.clear();
@@ -5525,7 +5499,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void removeAndAddAutomaticZenRule_wasSnoozed_isRestoredAsInactive() {
// Start with a rule.
mZenModeHelper.mConfig.automaticRules.clear();
@@ -5579,8 +5553,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void testRuleCleanup() throws Exception {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
Instant now = Instant.ofEpochMilli(1701796461000L);
Instant yesterday = now.minus(1, ChronoUnit.DAYS);
Instant aWeekAgo = now.minus(7, ChronoUnit.DAYS);
@@ -5637,7 +5611,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void getAutomaticZenRuleState_ownedRule_returnsRuleState() {
String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
new AutomaticZenRule.Builder("Rule", CONDITION_ID)
@@ -5662,7 +5636,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void getAutomaticZenRuleState_notOwnedRule_returnsStateUnknown() {
// Assume existence of a system-owned rule that is currently ACTIVE.
ZenRule systemRule = newZenRule("android", Instant.now(), null);
@@ -5678,7 +5652,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void setAutomaticZenRuleState_idForNotOwnedRule_ignored() {
// Assume existence of an other-package-owned rule that is currently ACTIVE.
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
@@ -5699,7 +5673,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void setAutomaticZenRuleState_conditionForNotOwnedRule_ignored() {
// Assume existence of an other-package-owned rule that is currently ACTIVE.
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
@@ -5720,7 +5694,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testCallbacks_policy() throws Exception {
setupZenConfig();
assertThat(mZenModeHelper.getNotificationPolicy().allowReminders()).isTrue();
@@ -5740,10 +5714,9 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void testCallbacks_consolidatedPolicy() throws Exception {
- setupZenConfig();
- assertThat(mZenModeHelper.getConsolidatedNotificationPolicy().allowAlarms()).isTrue();
+ assertThat(mZenModeHelper.getConsolidatedNotificationPolicy().allowMedia()).isTrue();
SettableFuture<Policy> futureConsolidatedPolicy = SettableFuture.create();
mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
@Override
@@ -5762,12 +5735,12 @@
new Condition(CONDITION_ID, "", STATE_TRUE), UPDATE_ORIGIN_APP, CUSTOM_PKG_UID);
Policy callbackPolicy = futureConsolidatedPolicy.get(1, TimeUnit.SECONDS);
- assertThat(callbackPolicy.allowAlarms()).isFalse();
+ assertThat(callbackPolicy.allowMedia()).isFalse();
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_createsImplicitRuleAndActivatesIt() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
@@ -5777,13 +5750,13 @@
.comparingElementsUsing(IGNORE_METADATA)
.containsExactly(
expectedImplicitRule(CUSTOM_PKG_NAME, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
- mZenModeHelper.mConfig.toZenPolicy(), // copy of global config
+ mZenModeHelper.mConfig.getZenPolicy(), // copy of global config
true));
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_updatesImplicitRuleAndActivatesIt() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
@@ -5798,12 +5771,12 @@
.comparingElementsUsing(IGNORE_METADATA)
.containsExactly(
expectedImplicitRule(CUSTOM_PKG_NAME, ZEN_MODE_ALARMS,
- mZenModeHelper.mConfig.toZenPolicy(), // copy of global config
+ mZenModeHelper.mConfig.getZenPolicy(), // copy of global config
true));
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_ruleCustomized_doesNotUpdateRule() {
mZenModeHelper.mConfig.automaticRules.clear();
String pkg = mContext.getPackageName();
@@ -5835,7 +5808,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_ruleCustomizedButNotFilter_updatesRule() {
mZenModeHelper.mConfig.automaticRules.clear();
String pkg = mContext.getPackageName();
@@ -5866,8 +5839,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_modeOff_deactivatesImplicitRule() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(mPkg, CUSTOM_PKG_UID,
ZEN_MODE_IMPORTANT_INTERRUPTIONS);
@@ -5883,8 +5856,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_modeOffButNoPreviousRule_ignored() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
@@ -5894,8 +5867,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_update_unsnoozesRule() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
@@ -5915,8 +5888,8 @@
}
@Test
+ @DisableFlags(FLAG_MODES_API)
public void applyGlobalZenModeAsImplicitZenRule_flagOff_ignored() {
- mSetFlagsRule.disableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
withoutWtfCrash(
@@ -5928,8 +5901,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void applyGlobalPolicyAsImplicitZenRule_createsImplicitRule() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
Policy policy = new Policy(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS,
@@ -5952,8 +5925,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void applyGlobalPolicyAsImplicitZenRule_updatesImplicitRule() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
Policy original = new Policy(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS,
@@ -5983,7 +5956,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void applyGlobalPolicyAsImplicitZenRule_ruleCustomized_doesNotUpdateRule() {
mZenModeHelper.mConfig.automaticRules.clear();
String pkg = mContext.getPackageName();
@@ -5995,7 +5968,7 @@
// Store this for checking later.
ZenPolicy originalEffectiveZenPolicy = new ZenPolicy.Builder(
- mZenModeHelper.mConfig.toZenPolicy()).allowMedia(true).build();
+ mZenModeHelper.mConfig.getZenPolicy()).allowMedia(true).build();
// From user, update that rule's policy.
AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId);
@@ -6023,7 +5996,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ @EnableFlags(FLAG_MODES_API)
public void applyGlobalPolicyAsImplicitZenRule_ruleCustomizedButNotZenPolicy_updatesRule() {
mZenModeHelper.mConfig.automaticRules.clear();
String pkg = mContext.getPackageName();
@@ -6035,7 +6008,7 @@
// Store this for checking later.
ZenPolicy originalEffectiveZenPolicy = new ZenPolicy.Builder(
- mZenModeHelper.mConfig.toZenPolicy()).allowMedia(true).build();
+ mZenModeHelper.mConfig.getZenPolicy()).allowMedia(true).build();
// From user, update something in that rule, but not the ZenPolicy.
AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId);
@@ -6060,8 +6033,8 @@
}
@Test
+ @DisableFlags(FLAG_MODES_API)
public void applyGlobalPolicyAsImplicitZenRule_flagOff_ignored() {
- mSetFlagsRule.disableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
withoutWtfCrash(
@@ -6072,8 +6045,8 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void getNotificationPolicyFromImplicitZenRule_returnsSetPolicy() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
Policy writtenPolicy = new Policy(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS,
PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED,
Policy.getAllSuppressedVisualEffects(), STATE_FALSE,
@@ -6088,32 +6061,30 @@
}
@Test
+ @EnableFlags(FLAG_MODES_API)
+ @DisableFlags(FLAG_MODES_UI)
public void getNotificationPolicyFromImplicitZenRule_ruleWithoutPolicy_copiesGlobalPolicy() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
- mZenModeHelper.mConfig.allowCalls = true;
- mZenModeHelper.mConfig.allowConversations = false;
-
// Implicit rule will get the global policy at the time of rule creation.
mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
- ZEN_MODE_ALARMS);
+ ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- // If the policy then changes afterwards, we should keep the snapshotted version.
- mZenModeHelper.mConfig.allowCalls = false;
-
+ // If the policy then changes afterwards, it should inherit updates because user cannot
+ // edit the policy in the UI.
+ mZenModeHelper.setNotificationPolicy(new Policy(PRIORITY_CATEGORY_ALARMS, 0, 0),
+ UPDATE_ORIGIN_APP, 1);
Policy readPolicy = mZenModeHelper.getNotificationPolicyFromImplicitZenRule(
CUSTOM_PKG_NAME);
assertThat(readPolicy).isNotNull();
- assertThat(readPolicy.allowCalls()).isTrue();
- assertThat(readPolicy.allowConversations()).isFalse();
+ assertThat(readPolicy.allowCalls()).isFalse();
+ assertThat(readPolicy.allowAlarms()).isTrue();
}
@Test
+ @EnableFlags(FLAG_MODES_API)
public void getNotificationPolicyFromImplicitZenRule_noImplicitRule_returnsGlobalPolicy() {
- mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
-
- mZenModeHelper.mConfig.allowCalls = true;
- mZenModeHelper.mConfig.allowConversations = false;
+ Policy policy = new Policy(PRIORITY_CATEGORY_CALLS, PRIORITY_SENDERS_STARRED, 0);
+ mZenModeHelper.setNotificationPolicy(policy, UPDATE_ORIGIN_USER, 1);
Policy readPolicy = mZenModeHelper.getNotificationPolicyFromImplicitZenRule(
CUSTOM_PKG_NAME);
@@ -6124,8 +6095,8 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_API)
- @DisableFlags(Flags.FLAG_MODES_UI)
+ @EnableFlags(FLAG_MODES_API)
+ @DisableFlags(FLAG_MODES_UI)
public void setNotificationPolicy_updatesRulePolicies_ifRulePolicyIsDefaultOrGlobalPolicy() {
ZenPolicy defaultZenPolicy = mZenModeHelper.getDefaultZenPolicy();
Policy previousManualPolicy = mZenModeHelper.mConfig.toNotificationPolicy();
@@ -6185,6 +6156,35 @@
assertThat(storedRule.getIconResId()).isEqualTo(0);
}
+ @Test
+ @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ public void setManualZenRuleDeviceEffects_noPreexistingMode() {
+ ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
+ .setShouldDimWallpaper(true)
+ .build();
+ mZenModeHelper.setManualZenRuleDeviceEffects(effects, UPDATE_ORIGIN_USER, "settings", 1000);
+
+ assertThat(mZenModeHelper.getConfig().manualRule).isNotNull();
+ assertThat(mZenModeHelper.getConfig().isManualActive()).isFalse();
+ assertThat(mZenModeHelper.getConfig().manualRule.zenDeviceEffects).isEqualTo(effects);
+ }
+
+ @Test
+ @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ public void setManualZenRuleDeviceEffects_preexistingMode() {
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, Uri.EMPTY, UPDATE_ORIGIN_USER,
+ "create manual rule", "settings", 1000);
+
+ ZenDeviceEffects effects = new ZenDeviceEffects.Builder()
+ .setShouldDimWallpaper(true)
+ .build();
+ mZenModeHelper.setManualZenRuleDeviceEffects(effects, UPDATE_ORIGIN_USER, "settings", 1000);
+
+ assertThat(mZenModeHelper.getConfig().manualRule).isNotNull();
+ assertThat(mZenModeHelper.getConfig().isManualActive()).isFalse();
+ assertThat(mZenModeHelper.getConfig().manualRule.zenDeviceEffects).isEqualTo(effects);
+ }
+
private static void addZenRule(ZenModeConfig config, String id, String ownerPkg, int zenMode,
@Nullable ZenPolicy zenPolicy) {
ZenRule rule = new ZenRule();
@@ -6246,34 +6246,19 @@
// TODO: b/310620812 - Update setup methods to include allowChannels() when MODES_API is inlined
private void setupZenConfig() {
- mZenModeHelper.mZenMode = ZEN_MODE_OFF;
- mZenModeHelper.mConfig.allowAlarms = false;
- mZenModeHelper.mConfig.allowMedia = false;
- mZenModeHelper.mConfig.allowSystem = false;
- mZenModeHelper.mConfig.allowReminders = true;
- mZenModeHelper.mConfig.allowCalls = true;
- mZenModeHelper.mConfig.allowCallsFrom = PRIORITY_SENDERS_STARRED;
- mZenModeHelper.mConfig.allowMessages = true;
- mZenModeHelper.mConfig.allowConversations = true;
- mZenModeHelper.mConfig.allowEvents = true;
- mZenModeHelper.mConfig.allowRepeatCallers = true;
- mZenModeHelper.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
- mZenModeHelper.mConfig.manualRule = null;
- }
-
- private void setupZenConfigMaintained() {
- // config is still the same as when it was setup (setupZenConfig)
- assertFalse(mZenModeHelper.mConfig.allowAlarms);
- assertFalse(mZenModeHelper.mConfig.allowMedia);
- assertFalse(mZenModeHelper.mConfig.allowSystem);
- assertTrue(mZenModeHelper.mConfig.allowReminders);
- assertTrue(mZenModeHelper.mConfig.allowCalls);
- assertEquals(PRIORITY_SENDERS_STARRED, mZenModeHelper.mConfig.allowCallsFrom);
- assertTrue(mZenModeHelper.mConfig.allowMessages);
- assertTrue(mZenModeHelper.mConfig.allowConversations);
- assertTrue(mZenModeHelper.mConfig.allowEvents);
- assertTrue(mZenModeHelper.mConfig.allowRepeatCallers);
- assertEquals(SUPPRESSED_EFFECT_BADGE, mZenModeHelper.mConfig.suppressedVisualEffects);
+ Policy customPolicy = new Policy(PRIORITY_CATEGORY_REMINDERS
+ | PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_MESSAGES
+ | PRIORITY_CATEGORY_EVENTS | PRIORITY_CATEGORY_REPEAT_CALLERS
+ | PRIORITY_CATEGORY_CONVERSATIONS,
+ PRIORITY_SENDERS_STARRED,
+ PRIORITY_SENDERS_STARRED,
+ SUPPRESSED_EFFECT_BADGE,
+ 0,
+ CONVERSATION_SENDERS_IMPORTANT);
+ mZenModeHelper.setNotificationPolicy(customPolicy, UPDATE_ORIGIN_UNKNOWN, 1);
+ if (!Flags.modesUi()) {
+ mZenModeHelper.mConfig.manualRule = null;
+ }
}
private void checkDndProtoMatchesSetupZenConfig(DNDPolicyProto dndProto) {