Merge "Fix bug with clearing bubble to expand" into tm-qpr-dev
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index da5b88b..19de1a5 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3349,12 +3349,17 @@
ctor public TaskFragmentOrganizer(@NonNull java.util.concurrent.Executor);
method @NonNull public java.util.concurrent.Executor getExecutor();
method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken();
- method public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentInfo);
+ method public void onActivityReparentedToTask(@NonNull android.window.WindowContainerTransaction, int, @NonNull android.content.Intent, @NonNull android.os.IBinder);
+ method @Deprecated public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentInfo);
+ method public void onTaskFragmentAppeared(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.TaskFragmentInfo);
method @Deprecated public void onTaskFragmentError(@NonNull android.os.IBinder, @NonNull Throwable);
- method public void onTaskFragmentError(@NonNull android.os.IBinder, @Nullable android.window.TaskFragmentInfo, int, @NonNull Throwable);
- method public void onTaskFragmentInfoChanged(@NonNull android.window.TaskFragmentInfo);
- method public void onTaskFragmentParentInfoChanged(@NonNull android.os.IBinder, @NonNull android.content.res.Configuration);
- method public void onTaskFragmentVanished(@NonNull android.window.TaskFragmentInfo);
+ method public void onTaskFragmentError(@NonNull android.window.WindowContainerTransaction, @NonNull android.os.IBinder, @Nullable android.window.TaskFragmentInfo, int, @NonNull Throwable);
+ method @Deprecated public void onTaskFragmentInfoChanged(@NonNull android.window.TaskFragmentInfo);
+ method public void onTaskFragmentInfoChanged(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.TaskFragmentInfo);
+ method @Deprecated public void onTaskFragmentParentInfoChanged(@NonNull android.os.IBinder, @NonNull android.content.res.Configuration);
+ method public void onTaskFragmentParentInfoChanged(@NonNull android.window.WindowContainerTransaction, int, @NonNull android.content.res.Configuration);
+ method @Deprecated public void onTaskFragmentVanished(@NonNull android.window.TaskFragmentInfo);
+ method public void onTaskFragmentVanished(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.TaskFragmentInfo);
method @CallSuper public void registerOrganizer();
method @CallSuper public void unregisterOrganizer();
}
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index c9cc1a1..05c9fca 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -124,8 +124,13 @@
/**
* The maximum length for text fields in a NotificationChannel. Fields will be truncated at this
* limit.
+ * @hide
*/
- private static final int MAX_TEXT_LENGTH = 1000;
+ public static final int MAX_TEXT_LENGTH = 1000;
+ /**
+ * @hide
+ */
+ public static final int MAX_VIBRATION_LENGTH = 1000;
private static final String TAG_CHANNEL = "channel";
private static final String ATT_NAME = "name";
@@ -283,17 +288,17 @@
*/
protected NotificationChannel(Parcel in) {
if (in.readByte() != 0) {
- mId = in.readString();
+ mId = getTrimmedString(in.readString());
} else {
mId = null;
}
if (in.readByte() != 0) {
- mName = in.readString();
+ mName = getTrimmedString(in.readString());
} else {
mName = null;
}
if (in.readByte() != 0) {
- mDesc = in.readString();
+ mDesc = getTrimmedString(in.readString());
} else {
mDesc = null;
}
@@ -302,18 +307,22 @@
mLockscreenVisibility = in.readInt();
if (in.readByte() != 0) {
mSound = Uri.CREATOR.createFromParcel(in);
+ mSound = Uri.parse(getTrimmedString(mSound.toString()));
} else {
mSound = null;
}
mLights = in.readByte() != 0;
mVibration = in.createLongArray();
+ if (mVibration != null && mVibration.length > MAX_VIBRATION_LENGTH) {
+ mVibration = Arrays.copyOf(mVibration, MAX_VIBRATION_LENGTH);
+ }
mUserLockedFields = in.readInt();
mFgServiceShown = in.readByte() != 0;
mVibrationEnabled = in.readByte() != 0;
mShowBadge = in.readByte() != 0;
mDeleted = in.readByte() != 0;
if (in.readByte() != 0) {
- mGroup = in.readString();
+ mGroup = getTrimmedString(in.readString());
} else {
mGroup = null;
}
@@ -322,8 +331,8 @@
mBlockableSystem = in.readBoolean();
mAllowBubbles = in.readInt();
mOriginalImportance = in.readInt();
- mParentId = in.readString();
- mConversationId = in.readString();
+ mParentId = getTrimmedString(in.readString());
+ mConversationId = getTrimmedString(in.readString());
mDemoted = in.readBoolean();
mImportantConvo = in.readBoolean();
mDeletedTime = in.readLong();
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index f97415c..807bd57 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -20,6 +20,7 @@
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
+import android.content.pm.ParceledListSlice;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -43,8 +44,9 @@
/**
* The maximum length for text fields in a NotificationChannelGroup. Fields will be truncated at
* this limit.
+ * @hide
*/
- private static final int MAX_TEXT_LENGTH = 1000;
+ public static final int MAX_TEXT_LENGTH = 1000;
private static final String TAG_GROUP = "channelGroup";
private static final String ATT_NAME = "name";
@@ -66,7 +68,7 @@
private CharSequence mName;
private String mDescription;
private boolean mBlocked;
- private List<NotificationChannel> mChannels = new ArrayList<>();
+ private ParceledListSlice<NotificationChannel> mChannels;
// Bitwise representation of fields that have been changed by the user
private int mUserLockedFields;
@@ -90,17 +92,19 @@
*/
protected NotificationChannelGroup(Parcel in) {
if (in.readByte() != 0) {
- mId = in.readString();
+ mId = getTrimmedString(in.readString());
} else {
mId = null;
}
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mName = getTrimmedString(mName.toString());
if (in.readByte() != 0) {
- mDescription = in.readString();
+ mDescription = getTrimmedString(in.readString());
} else {
mDescription = null;
}
- in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader(), android.app.NotificationChannel.class);
+ mChannels = in.readParcelable(
+ NotificationChannelGroup.class.getClassLoader(), ParceledListSlice.class);
mBlocked = in.readBoolean();
mUserLockedFields = in.readInt();
}
@@ -120,14 +124,14 @@
} else {
dest.writeByte((byte) 0);
}
- TextUtils.writeToParcel(mName, dest, flags);
+ TextUtils.writeToParcel(mName.toString(), dest, flags);
if (mDescription != null) {
dest.writeByte((byte) 1);
dest.writeString(mDescription);
} else {
dest.writeByte((byte) 0);
}
- dest.writeParcelableList(mChannels, flags);
+ dest.writeParcelable(mChannels, flags);
dest.writeBoolean(mBlocked);
dest.writeInt(mUserLockedFields);
}
@@ -157,7 +161,7 @@
* Returns the list of channels that belong to this group
*/
public List<NotificationChannel> getChannels() {
- return mChannels;
+ return mChannels == null ? new ArrayList<>() : mChannels.getList();
}
/**
@@ -191,15 +195,8 @@
/**
* @hide
*/
- public void addChannel(NotificationChannel channel) {
- mChannels.add(channel);
- }
-
- /**
- * @hide
- */
public void setChannels(List<NotificationChannel> channels) {
- mChannels = channels;
+ mChannels = new ParceledListSlice<>(channels);
}
/**
@@ -334,7 +331,7 @@
proto.write(NotificationChannelGroupProto.NAME, mName.toString());
proto.write(NotificationChannelGroupProto.DESCRIPTION, mDescription);
proto.write(NotificationChannelGroupProto.IS_BLOCKED, mBlocked);
- for (NotificationChannel channel : mChannels) {
+ for (NotificationChannel channel : mChannels.getList()) {
channel.dumpDebug(proto, NotificationChannelGroupProto.CHANNELS);
}
proto.end(token);
diff --git a/core/java/android/attention/AttentionManagerInternal.java b/core/java/android/attention/AttentionManagerInternal.java
index 47bec61..24fe0db 100644
--- a/core/java/android/attention/AttentionManagerInternal.java
+++ b/core/java/android/attention/AttentionManagerInternal.java
@@ -83,11 +83,11 @@
}
/** Internal interface for proximity callback. */
- public abstract static class ProximityUpdateCallbackInternal {
+ public interface ProximityUpdateCallbackInternal {
/**
* @param distance the estimated distance of the user (in meter)
* The distance will be PROXIMITY_UNKNOWN if the proximity sensing was inconclusive.
*/
- public abstract void onProximityUpdate(double distance);
+ void onProximityUpdate(double distance);
}
}
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index a9d665c8..621eab5 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -1963,7 +1963,6 @@
}
private static Object mServiceLock = new Object();
- private static ISoundTriggerMiddlewareService mService;
/**
* Translate an exception thrown from interaction with the underlying service to an error code.
@@ -2217,20 +2216,12 @@
binder =
ServiceManager.getServiceOrThrow(
Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE);
- binder.linkToDeath(() -> {
- synchronized (mServiceLock) {
- mService = null;
- }
- }, 0);
- mService = ISoundTriggerMiddlewareService.Stub.asInterface(binder);
- break;
+ return ISoundTriggerMiddlewareService.Stub.asInterface(binder);
} catch (Exception e) {
Log.e(TAG, "Failed to bind to soundtrigger service", e);
}
}
- return mService;
}
-
}
/**
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 06c35b5..801d34d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -956,16 +956,7 @@
public static final int NUM_WIFI_BATCHED_SCAN_BINS = 5;
- /**
- * Note that these must match the constants in android.os.PowerManager.
- * Also, if the user activity types change, the BatteryStatsImpl.VERSION must
- * also be bumped.
- */
- static final String[] USER_ACTIVITY_TYPES = {
- "other", "button", "touch", "accessibility", "attention"
- };
-
- public static final int NUM_USER_ACTIVITY_TYPES = USER_ACTIVITY_TYPES.length;
+ public static final int NUM_USER_ACTIVITY_TYPES = PowerManager.USER_ACTIVITY_EVENT_MAX + 1;
public abstract void noteUserActivityLocked(int type);
public abstract boolean hasUserActivity();
@@ -6177,7 +6168,7 @@
}
sb.append(val);
sb.append(" ");
- sb.append(Uid.USER_ACTIVITY_TYPES[i]);
+ sb.append(PowerManager.userActivityEventToString(i));
}
}
if (hasData) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 13ca2c3..8a203e0 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -345,6 +345,44 @@
public static final int USER_ACTIVITY_EVENT_DEVICE_STATE = 6;
/**
+ * @hide
+ */
+ public static final int USER_ACTIVITY_EVENT_MAX = USER_ACTIVITY_EVENT_DEVICE_STATE;
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = { "USER_ACTIVITY_EVENT_" }, value = {
+ USER_ACTIVITY_EVENT_OTHER,
+ USER_ACTIVITY_EVENT_BUTTON,
+ USER_ACTIVITY_EVENT_TOUCH,
+ USER_ACTIVITY_EVENT_ACCESSIBILITY,
+ USER_ACTIVITY_EVENT_ATTENTION,
+ USER_ACTIVITY_EVENT_FACE_DOWN,
+ USER_ACTIVITY_EVENT_DEVICE_STATE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface UserActivityEvent{}
+
+ /**
+ *
+ * Convert the user activity event to a string for debugging purposes.
+ * @hide
+ */
+ public static String userActivityEventToString(@UserActivityEvent int userActivityEvent) {
+ switch (userActivityEvent) {
+ case USER_ACTIVITY_EVENT_OTHER: return "other";
+ case USER_ACTIVITY_EVENT_BUTTON: return "button";
+ case USER_ACTIVITY_EVENT_TOUCH: return "touch";
+ case USER_ACTIVITY_EVENT_ACCESSIBILITY: return "accessibility";
+ case USER_ACTIVITY_EVENT_ATTENTION: return "attention";
+ case USER_ACTIVITY_EVENT_FACE_DOWN: return "faceDown";
+ case USER_ACTIVITY_EVENT_DEVICE_STATE: return "deviceState";
+ default: return Integer.toString(userActivityEvent);
+ }
+ }
+
+ /**
* User activity flag: If already dimmed, extend the dim timeout
* but do not brighten. This flag is useful for keeping the screen on
* a little longer without causing a visible change such as when
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index d656604..b2f7c60 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1971,7 +1971,8 @@
/** @hide */
public UserManager(Context context, IUserManager service) {
mService = service;
- mContext = context.getApplicationContext();
+ Context appContext = context.getApplicationContext();
+ mContext = (appContext == null ? context : appContext);
mUserId = context.getUserId();
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a76524a..592673e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10591,6 +10591,13 @@
public static final String MEDIA_CONTROLS_RESUME = "qs_media_resumption";
/**
+ * Whether to enable media controls on lock screen.
+ * When enabled, media controls will appear on lock screen.
+ * @hide
+ */
+ public static final String MEDIA_CONTROLS_LOCK_SCREEN = "media_controls_lock_screen";
+
+ /**
* Controls whether contextual suggestions can be shown in the media controls.
* @hide
*/
diff --git a/core/java/android/service/voice/HotwordDetectedResult.java b/core/java/android/service/voice/HotwordDetectedResult.java
index 7234145..ab71459 100644
--- a/core/java/android/service/voice/HotwordDetectedResult.java
+++ b/core/java/android/service/voice/HotwordDetectedResult.java
@@ -95,6 +95,16 @@
/** Limits the max value for the triggered audio channel. */
private static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE = 63;
+ /**
+ * The bundle key for proximity value
+ *
+ * TODO(b/238896013): Move the proximity logic out of bundle to proper API.
+ *
+ * @hide
+ */
+ public static final String EXTRA_PROXIMITY_METERS =
+ "android.service.voice.extra.PROXIMITY_METERS";
+
/** Confidence level in the trigger outcome. */
@HotwordConfidenceLevelValue
private final int mConfidenceLevel;
@@ -197,6 +207,14 @@
* <p>The use of this method is discouraged, and support for it will be removed in future
* versions of Android.
*
+ * <p>After the trigger happens, a special case of proximity-related extra, with the key of
+ * 'android.service.voice.extra.PROXIMITY_METERS' and the value of distance in meters (double),
+ * will be stored to enable proximity logic. The proximity meters is provided by the system,
+ * on devices that support detecting proximity of nearby users, to help disambiguate which
+ * nearby device should respond. When the proximity is unknown, the proximity value will not
+ * be stored. This mapping will be excluded from the max bundle size calculation because this
+ * mapping is included after the result is returned from the hotword detector service.
+ *
* <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents
* that can be used to communicate with other processes.
*/
@@ -315,8 +333,23 @@
"audioChannel");
}
if (!mExtras.isEmpty()) {
- Preconditions.checkArgumentInRange(getParcelableSize(mExtras), 0, getMaxBundleSize(),
- "extras");
+ // Remove the proximity key from the bundle before checking the bundle size. The
+ // proximity value is added after the privileged module and can avoid the
+ // maxBundleSize limitation.
+ if (mExtras.containsKey(EXTRA_PROXIMITY_METERS)) {
+ double proximityMeters = mExtras.getDouble(EXTRA_PROXIMITY_METERS);
+ mExtras.remove(EXTRA_PROXIMITY_METERS);
+ // Skip checking parcelable size if the new bundle size is 0. Newly empty bundle
+ // has parcelable size of 4, but the default bundle has parcelable size of 0.
+ if (mExtras.size() > 0) {
+ Preconditions.checkArgumentInRange(getParcelableSize(mExtras), 0,
+ getMaxBundleSize(), "extras");
+ }
+ mExtras.putDouble(EXTRA_PROXIMITY_METERS, proximityMeters);
+ } else {
+ Preconditions.checkArgumentInRange(getParcelableSize(mExtras), 0,
+ getMaxBundleSize(), "extras");
+ }
}
}
@@ -513,6 +546,14 @@
* <p>The use of this method is discouraged, and support for it will be removed in future
* versions of Android.
*
+ * <p>After the trigger happens, a special case of proximity-related extra, with the key of
+ * 'android.service.voice.extra.PROXIMITY_METERS' and the value of distance in meters (double),
+ * will be stored to enable proximity logic. The proximity meters is provided by the system,
+ * on devices that support detecting proximity of nearby users, to help disambiguate which
+ * nearby device should respond. When the proximity is unknown, the proximity value will not
+ * be stored. This mapping will be excluded from the max bundle size calculation because this
+ * mapping is included after the result is returned from the hotword detector service.
+ *
* <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents
* that can be used to communicate with other processes.
*/
@@ -813,6 +854,14 @@
* <p>The use of this method is discouraged, and support for it will be removed in future
* versions of Android.
*
+ * <p>After the trigger happens, a special case of proximity-related extra, with the key of
+ * 'android.service.voice.extra.PROXIMITY_METERS' and the value of distance in meters (double),
+ * will be stored to enable proximity logic. The proximity meters is provided by the system,
+ * on devices that support detecting proximity of nearby users, to help disambiguate which
+ * nearby device should respond. When the proximity is unknown, the proximity value will not
+ * be stored. This mapping will be excluded from the max bundle size calculation because this
+ * mapping is included after the result is returned from the hotword detector service.
+ *
* <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents
* that can be used to communicate with other processes.
*/
@@ -882,10 +931,10 @@
}
@DataClass.Generated(
- time = 1625541522353L,
+ time = 1658357814396L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java",
- inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate static final int LIMIT_HOTWORD_OFFSET_MAX_VALUE\nprivate static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int sMaxBundleSize\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\npublic static int getParcelableSize(android.os.Parcelable)\npublic static int getUsageSize(android.service.voice.HotwordDetectedResult)\nprivate static int bitCount(long)\nprivate void onConstructed()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate static final int LIMIT_HOTWORD_OFFSET_MAX_VALUE\nprivate static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE\npublic static final java.lang.String EXTRA_PROXIMITY_METERS\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int sMaxBundleSize\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\npublic static int getParcelableSize(android.os.Parcelable)\npublic static int getUsageSize(android.service.voice.HotwordDetectedResult)\nprivate static int bitCount(long)\nprivate void onConstructed()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index a2cb1d5..0e3bcd1 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -314,6 +314,9 @@
(int) (startValue.right + fraction * (endValue.right - startValue.right)),
(int) (startValue.bottom + fraction * (endValue.bottom - startValue.bottom)));
+ /** Logging listener. */
+ private WindowInsetsAnimationControlListener mLoggingListener;
+
/**
* The default implementation of listener, to be used by InsetsController and InsetsPolicy to
* animate insets.
@@ -330,6 +333,7 @@
private final long mDurationMs;
private final boolean mDisable;
private final int mFloatingImeBottomInset;
+ private final WindowInsetsAnimationControlListener mLoggingListener;
private final ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
new ThreadLocal<AnimationHandler>() {
@@ -343,7 +347,7 @@
public InternalAnimationControlListener(boolean show, boolean hasAnimationCallbacks,
@InsetsType int requestedTypes, @Behavior int behavior, boolean disable,
- int floatingImeBottomInset) {
+ int floatingImeBottomInset, WindowInsetsAnimationControlListener loggingListener) {
mShow = show;
mHasAnimationCallbacks = hasAnimationCallbacks;
mRequestedTypes = requestedTypes;
@@ -351,12 +355,16 @@
mDurationMs = calculateDurationMs();
mDisable = disable;
mFloatingImeBottomInset = floatingImeBottomInset;
+ mLoggingListener = loggingListener;
}
@Override
public void onReady(WindowInsetsAnimationController controller, int types) {
mController = controller;
if (DEBUG) Log.d(TAG, "default animation onReady types: " + types);
+ if (mLoggingListener != null) {
+ mLoggingListener.onReady(controller, types);
+ }
if (mDisable) {
onAnimationFinish();
@@ -410,6 +418,9 @@
public void onFinished(WindowInsetsAnimationController controller) {
if (DEBUG) Log.d(TAG, "InternalAnimationControlListener onFinished types:"
+ Type.toString(mRequestedTypes));
+ if (mLoggingListener != null) {
+ mLoggingListener.onFinished(controller);
+ }
}
@Override
@@ -420,6 +431,9 @@
}
if (DEBUG) Log.d(TAG, "InternalAnimationControlListener onCancelled types:"
+ mRequestedTypes);
+ if (mLoggingListener != null) {
+ mLoggingListener.onCancelled(controller);
+ }
}
protected Interpolator getInsetsInterpolator() {
@@ -1147,6 +1161,13 @@
updateRequestedVisibilities();
}
+ // TODO(b/242962223): Make this setter restrictive.
+ @Override
+ public void setSystemDrivenInsetsAnimationLoggingListener(
+ @Nullable WindowInsetsAnimationControlListener listener) {
+ mLoggingListener = listener;
+ }
+
/**
* @return Pair of (types ready to animate, IME ready to animate).
*/
@@ -1460,7 +1481,8 @@
boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks();
final InternalAnimationControlListener listener = new InternalAnimationControlListener(
show, hasAnimationCallbacks, types, mHost.getSystemBarsBehavior(),
- skipAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP));
+ skipAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP),
+ mLoggingListener);
// We are about to playing the default animation (show/hide). Passing a null frame indicates
// the controlled types should be animated regardless of the frame.
diff --git a/core/java/android/view/PendingInsetsController.java b/core/java/android/view/PendingInsetsController.java
index c61baf6..3fe9110 100644
--- a/core/java/android/view/PendingInsetsController.java
+++ b/core/java/android/view/PendingInsetsController.java
@@ -44,6 +44,7 @@
private ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
= new ArrayList<>();
private int mCaptionInsetsHeight = 0;
+ private WindowInsetsAnimationControlListener mLoggingListener;
@Override
public void show(int types) {
@@ -176,6 +177,9 @@
controller.addOnControllableInsetsChangedListener(
mControllableInsetsChangedListeners.get(i));
}
+ if (mLoggingListener != null) {
+ controller.setSystemDrivenInsetsAnimationLoggingListener(mLoggingListener);
+ }
// Reset all state so it doesn't get applied twice just in case
mRequests.clear();
@@ -184,7 +188,7 @@
mAppearance = 0;
mAppearanceMask = 0;
mAnimationsDisabled = false;
-
+ mLoggingListener = null;
// After replaying, we forward everything directly to the replayed instance.
mReplayedInsetsController = controller;
}
@@ -198,6 +202,16 @@
}
@Override
+ public void setSystemDrivenInsetsAnimationLoggingListener(
+ @Nullable WindowInsetsAnimationControlListener listener) {
+ if (mReplayedInsetsController != null) {
+ mReplayedInsetsController.setSystemDrivenInsetsAnimationLoggingListener(listener);
+ } else {
+ mLoggingListener = listener;
+ }
+ }
+
+ @Override
public void controlWindowInsetsAnimation(@InsetsType int types, long durationMillis,
@Nullable Interpolator interpolator,
CancellationSignal cancellationSignal,
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 5721fa6..3acb053 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -28,8 +28,8 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
-import android.window.WindowTokenClient;
import android.view.accessibility.IAccessibilityEmbeddedConnection;
+import android.window.WindowTokenClient;
import java.util.Objects;
@@ -271,14 +271,8 @@
/** @hide */
public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d,
@NonNull WindowlessWindowManager wwm) {
- this(c, d, wwm, false /* useSfChoreographer */);
- }
-
- /** @hide */
- public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d,
- @NonNull WindowlessWindowManager wwm, boolean useSfChoreographer) {
mWm = wwm;
- mViewRoot = new ViewRootImpl(c, d, mWm, new WindowlessWindowLayout(), useSfChoreographer);
+ mViewRoot = new ViewRootImpl(c, d, mWm, new WindowlessWindowLayout());
addConfigCallback(c, d);
WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index af57f3b..ec6b4ac 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -905,17 +905,11 @@
private String mTag = TAG;
public ViewRootImpl(Context context, Display display) {
- this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout(),
- false /* useSfChoreographer */);
+ this(context, display, WindowManagerGlobal.getWindowSession(), new WindowLayout());
}
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
WindowLayout windowLayout) {
- this(context, display, session, windowLayout, false /* useSfChoreographer */);
- }
-
- public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
- WindowLayout windowLayout, boolean useSfChoreographer) {
mContext = context;
mWindowSession = session;
mWindowLayout = windowLayout;
@@ -947,8 +941,7 @@
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = new PhoneFallbackEventHandler(context);
// TODO(b/222696368): remove getSfInstance usage and use vsyncId for transactions
- mChoreographer = useSfChoreographer
- ? Choreographer.getSfInstance() : Choreographer.getInstance();
+ mChoreographer = Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mInsetsController = new InsetsController(new ViewRootInsetsControllerHost(this));
mHandwritingInitiator = new HandwritingInitiator(mViewConfiguration,
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index 227b9f4..63f9e13 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -201,6 +201,21 @@
@NonNull WindowInsetsAnimationControlListener listener);
/**
+ * Lets the application add non-controllable listener object that can be called back
+ * when animation is invoked by the system by host calling methods such as {@link #show} or
+ * {@link #hide}.
+ *
+ * The listener is supposed to be used for logging only, using the control or
+ * relying on the timing of the callback in any other way is not supported.
+ *
+ * @param listener The {@link WindowInsetsAnimationControlListener} that gets called when
+ * the animation is driven by the system and not the host
+ * @hide
+ */
+ void setSystemDrivenInsetsAnimationLoggingListener(
+ @Nullable WindowInsetsAnimationControlListener listener);
+
+ /**
* Controls the appearance of system bars.
* <p>
* For example, the following statement adds {@link #APPEARANCE_LIGHT_STATUS_BARS}:
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 67352c0..2195b83 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1023,6 +1023,14 @@
}
}
+ /**
+ * Ensure scales are between 0 and 20.
+ * @hide
+ */
+ static float fixScale(float scale) {
+ return Math.max(Math.min(scale, 20), 0);
+ }
+
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
/**
* X position for this window. With the default gravity it is ignored.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index cae4868..b5a742b 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -89,6 +89,7 @@
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewRootImpl;
+import android.view.WindowInsets;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.autofill.AutofillManager;
import android.window.ImeOnBackInvokedDispatcher;
@@ -2122,8 +2123,9 @@
null /* icProto */);
synchronized (mH) {
final View view = getServedViewLocked();
- if (mImeInsetsConsumer != null && view != null) {
- if (mImeInsetsConsumer.isRequestedVisible()) {
+ if (view != null) {
+ final WindowInsets rootInsets = view.getRootWindowInsets();
+ if (rootInsets != null && rootInsets.isVisible(WindowInsets.Type.ime())) {
hideSoftInputFromWindow(view.getWindowToken(), hideFlags, null,
SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT);
} else {
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 84302dd..c43cf55 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -16,7 +16,7 @@
package android.window;
-import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENT_TO_TASK;
+import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
@@ -26,6 +26,7 @@
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.content.Intent;
import android.content.res.Configuration;
@@ -147,16 +148,76 @@
}
}
- /** Called when a TaskFragment is created and organized by this organizer. */
+ /**
+ * Called when a TaskFragment is created and organized by this organizer.
+ *
+ * @param taskFragmentInfo Info of the TaskFragment that is created.
+ * @deprecated Use {@link #onTaskFragmentAppeared(WindowContainerTransaction, TaskFragmentInfo)}
+ * instead.
+ */
+ @Deprecated
public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {}
- /** Called when the status of an organized TaskFragment is changed. */
+ /**
+ * Called when a TaskFragment is created and organized by this organizer.
+ *
+ * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
+ * need to call {@link #applyTransaction} as it will be applied by the caller.
+ * @param taskFragmentInfo Info of the TaskFragment that is created.
+ */
+ public void onTaskFragmentAppeared(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo) {
+ // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next release.
+ onTaskFragmentAppeared(taskFragmentInfo);
+ }
+
+ /**
+ * Called when the status of an organized TaskFragment is changed.
+ *
+ * @param taskFragmentInfo Info of the TaskFragment that is changed.
+ * @deprecated Use {@link #onTaskFragmentInfoChanged(WindowContainerTransaction,
+ * TaskFragmentInfo)} instead.
+ */
+ @Deprecated
public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {}
- /** Called when an organized TaskFragment is removed. */
+ /**
+ * Called when the status of an organized TaskFragment is changed.
+ *
+ * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
+ * need to call {@link #applyTransaction} as it will be applied by the caller.
+ * @param taskFragmentInfo Info of the TaskFragment that is changed.
+ */
+ public void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo) {
+ // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next release.
+ onTaskFragmentInfoChanged(taskFragmentInfo);
+ }
+
+ /**
+ * Called when an organized TaskFragment is removed.
+ *
+ * @param taskFragmentInfo Info of the TaskFragment that is removed.
+ * @deprecated Use {@link #onTaskFragmentVanished(WindowContainerTransaction,
+ * TaskFragmentInfo)} instead.
+ */
+ @Deprecated
public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {}
/**
+ * Called when an organized TaskFragment is removed.
+ *
+ * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
+ * need to call {@link #applyTransaction} as it will be applied by the caller.
+ * @param taskFragmentInfo Info of the TaskFragment that is removed.
+ */
+ public void onTaskFragmentVanished(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo) {
+ // TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next release.
+ onTaskFragmentVanished(taskFragmentInfo);
+ }
+
+ /**
* Called when the parent leaf Task of organized TaskFragments is changed.
* When the leaf Task is changed, the organizer may want to update the TaskFragments in one
* transaction.
@@ -164,7 +225,13 @@
* For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new
* Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override
* bounds.
+ *
+ * @param fragmentToken The parent Task this TaskFragment is changed.
+ * @param parentConfig Config of the parent Task.
+ * @deprecated Use {@link #onTaskFragmentParentInfoChanged(WindowContainerTransaction, int,
+ * Configuration)} instead.
*/
+ @Deprecated
public void onTaskFragmentParentInfoChanged(
@NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {}
@@ -176,9 +243,14 @@
* For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new
* Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override
* bounds.
- * @hide
+ *
+ * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
+ * need to call {@link #applyTransaction} as it will be applied by the caller.
+ * @param taskId Id of the parent Task that is changed.
+ * @param parentConfig Config of the parent Task.
*/
- public void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig) {
+ public void onTaskFragmentParentInfoChanged(@NonNull WindowContainerTransaction wct, int taskId,
+ @NonNull Configuration parentConfig) {
// TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next release.
final List<IBinder> tokens = mTaskIdToFragmentTokens.get(taskId);
if (tokens == null || tokens.isEmpty()) {
@@ -196,9 +268,8 @@
* @param errorCallbackToken token set in
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)}
* @param exception exception from the server side.
- *
- * @deprecated Use {@link #onTaskFragmentError(IBinder, TaskFragmentInfo, int, Throwable)}
- * instead.
+ * @deprecated Use {@link #onTaskFragmentError(WindowContainerTransaction, IBinder,
+ * TaskFragmentInfo, int, Throwable)} instead.
*/
@Deprecated
public void onTaskFragmentError(
@@ -208,6 +279,8 @@
* Called when the {@link WindowContainerTransaction} created with
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
*
+ * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
+ * need to call {@link #applyTransaction} as it will be applied by the caller.
* @param errorCallbackToken token set in
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)}
* @param taskFragmentInfo The {@link TaskFragmentInfo}. This could be {@code null} if no
@@ -216,7 +289,7 @@
* transaction operation.
* @param exception exception from the server side.
*/
- public void onTaskFragmentError(
+ public void onTaskFragmentError(@NonNull WindowContainerTransaction wct,
@NonNull IBinder errorCallbackToken, @Nullable TaskFragmentInfo taskFragmentInfo,
int opType, @NonNull Throwable exception) {
// Doing so to keep compatibility. This will be removed in the next release.
@@ -226,9 +299,11 @@
/**
* Called when an Activity is reparented to the Task with organized TaskFragment. For example,
* when an Activity enters and then exits Picture-in-picture, it will be reparented back to its
- * orginial Task. In this case, we need to notify the organizer so that it can check if the
+ * original Task. In this case, we need to notify the organizer so that it can check if the
* Activity matches any split rule.
*
+ * @param wct The {@link WindowContainerTransaction} to make any changes with if needed. No
+ * need to call {@link #applyTransaction} as it will be applied by the caller.
* @param taskId The Task that the activity is reparented to.
* @param activityIntent The intent that the activity is original launched with.
* @param activityToken If the activity belongs to the same process as the organizer, this
@@ -236,20 +311,23 @@
* different process, the server will generate a temporary token that
* the organizer can use to reparent the activity through
* {@link WindowContainerTransaction} if needed.
- * @hide
*/
- public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
- @NonNull IBinder activityToken) {}
+ public void onActivityReparentedToTask(@NonNull WindowContainerTransaction wct,
+ int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken) {}
/**
* Called when the transaction is ready so that the organizer can update the TaskFragments based
* on the changes in transaction.
+ * Note: {@link WindowOrganizer#applyTransaction} permission requirement is conditional for
+ * {@link TaskFragmentOrganizer}.
+ * @see com.android.server.wm.WindowOrganizerController#enforceTaskPermission
* @hide
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
for (TaskFragmentTransaction.Change change : changes) {
- // TODO(b/240519866): apply all changes in one WCT.
final int taskId = change.getTaskId();
switch (change.getType()) {
case TYPE_TASK_FRAGMENT_APPEARED:
@@ -262,10 +340,10 @@
onTaskFragmentParentInfoChanged(change.getTaskFragmentToken(),
mTaskIdToConfigurations.get(taskId));
- onTaskFragmentAppeared(change.getTaskFragmentInfo());
+ onTaskFragmentAppeared(wct, change.getTaskFragmentInfo());
break;
case TYPE_TASK_FRAGMENT_INFO_CHANGED:
- onTaskFragmentInfoChanged(change.getTaskFragmentInfo());
+ onTaskFragmentInfoChanged(wct, change.getTaskFragmentInfo());
break;
case TYPE_TASK_FRAGMENT_VANISHED:
// TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next
@@ -279,18 +357,19 @@
}
}
- onTaskFragmentVanished(change.getTaskFragmentInfo());
+ onTaskFragmentVanished(wct, change.getTaskFragmentInfo());
break;
case TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED:
// TODO(b/240519866): doing so to keep CTS compatibility. Remove in the next
// release.
mTaskIdToConfigurations.put(taskId, change.getTaskConfiguration());
- onTaskFragmentParentInfoChanged(taskId, change.getTaskConfiguration());
+ onTaskFragmentParentInfoChanged(wct, taskId, change.getTaskConfiguration());
break;
case TYPE_TASK_FRAGMENT_ERROR:
final Bundle errorBundle = change.getErrorBundle();
onTaskFragmentError(
+ wct,
change.getErrorCallbackToken(),
errorBundle.getParcelable(
KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO, TaskFragmentInfo.class),
@@ -298,8 +377,9 @@
errorBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION,
java.lang.Throwable.class));
break;
- case TYPE_ACTIVITY_REPARENT_TO_TASK:
- onActivityReparentToTask(
+ case TYPE_ACTIVITY_REPARENTED_TO_TASK:
+ onActivityReparentedToTask(
+ wct,
change.getTaskId(),
change.getActivityIntent(),
change.getActivityToken());
@@ -309,6 +389,8 @@
"Unknown TaskFragmentEvent=" + change.getType());
}
}
+ // TODO(b/240519866): notify TaskFragmentOrganizerController that the transition is done.
+ applyTransaction(wct);
}
@Override
diff --git a/core/java/android/window/TaskFragmentTransaction.java b/core/java/android/window/TaskFragmentTransaction.java
index 755864f..07e8e8c 100644
--- a/core/java/android/window/TaskFragmentTransaction.java
+++ b/core/java/android/window/TaskFragmentTransaction.java
@@ -122,7 +122,7 @@
* then exits Picture-in-picture, it will be reparented back to its original Task. In this case,
* we need to notify the organizer so that it can check if the Activity matches any split rule.
*/
- public static final int TYPE_ACTIVITY_REPARENT_TO_TASK = 6;
+ public static final int TYPE_ACTIVITY_REPARENTED_TO_TASK = 6;
@IntDef(prefix = { "TYPE_" }, value = {
TYPE_TASK_FRAGMENT_APPEARED,
@@ -130,7 +130,7 @@
TYPE_TASK_FRAGMENT_VANISHED,
TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED,
TYPE_TASK_FRAGMENT_ERROR,
- TYPE_ACTIVITY_REPARENT_TO_TASK
+ TYPE_ACTIVITY_REPARENTED_TO_TASK
})
@Retention(RetentionPolicy.SOURCE)
@interface ChangeType {}
@@ -247,7 +247,7 @@
/**
* Intent of the activity that is reparented to the Task for
- * {@link #TYPE_ACTIVITY_REPARENT_TO_TASK}.
+ * {@link #TYPE_ACTIVITY_REPARENTED_TO_TASK}.
*/
public Change setActivityIntent(@NonNull Intent intent) {
mActivityIntent = requireNonNull(intent);
@@ -255,7 +255,7 @@
}
/**
- * Token of the reparent activity for {@link #TYPE_ACTIVITY_REPARENT_TO_TASK}.
+ * Token of the reparent activity for {@link #TYPE_ACTIVITY_REPARENTED_TO_TASK}.
* If the activity belongs to the same process as the organizer, this will be the actual
* activity token; if the activity belongs to a different process, the server will generate
* a temporary token that the organizer can use to reparent the activity through
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
index a611d65d..6bc7ac6 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
@@ -168,6 +168,29 @@
}
/**
+ * Logs the duration for the window magnifier's following typing focus session.
+ *
+ * @param duration The duration of a triple-tap-and-hold activation session.
+ */
+ public static void logMagnificationFollowTypingFocusSession(long duration) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.MAGNIFICATION_FOLLOW_TYPING_FOCUS_ACTIVATED_SESSION_REPORTED,
+ duration);
+ }
+
+ /**
+ * Logs the duration for the magnification session which is activated by the triple tap and
+ * hold gesture.
+ *
+ * @param duration The duration of a triple-tap-and-hold activation session.
+ */
+ public static void logMagnificationTripleTapAndHoldSession(long duration) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.MAGNIFICATION_TRIPLE_TAP_AND_HOLD_ACTIVATED_SESSION_REPORTED,
+ duration);
+ }
+
+ /**
* Logs the warning status of the non-a11yTool service. Calls this when the warning status is
* changed.
*
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 98d4c59..06473b5 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -6144,7 +6144,8 @@
}
@GuardedBy("this")
- public void noteUserActivityLocked(int uid, int event, long elapsedRealtimeMs, long uptimeMs) {
+ public void noteUserActivityLocked(int uid, @PowerManager.UserActivityEvent int event,
+ long elapsedRealtimeMs, long uptimeMs) {
if (mOnBatteryInternal) {
uid = mapUid(uid);
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteUserActivityLocked(event);
@@ -9956,14 +9957,14 @@
}
@Override
- public void noteUserActivityLocked(int type) {
+ public void noteUserActivityLocked(@PowerManager.UserActivityEvent int event) {
if (mUserActivityCounters == null) {
initUserActivityLocked();
}
- if (type >= 0 && type < NUM_USER_ACTIVITY_TYPES) {
- mUserActivityCounters[type].stepAtomic();
+ if (event >= 0 && event < NUM_USER_ACTIVITY_TYPES) {
+ mUserActivityCounters[event].stepAtomic();
} else {
- Slog.w(TAG, "Unknown user activity type " + type + " was specified.",
+ Slog.w(TAG, "Unknown user activity event " + event + " was specified.",
new Throwable());
}
}
diff --git a/core/java/com/android/internal/view/inline/InlineTooltipUi.java b/core/java/com/android/internal/view/inline/InlineTooltipUi.java
index 3eae89e..836786d 100644
--- a/core/java/com/android/internal/view/inline/InlineTooltipUi.java
+++ b/core/java/com/android/internal/view/inline/InlineTooltipUi.java
@@ -170,9 +170,9 @@
int delayTimeMs = mShowDelayConfigMs;
try {
- final float scale = Settings.Global.getFloat(
+ final float scale = WindowManager.fixScale(Settings.Global.getFloat(
anchor.getContext().getContentResolver(),
- Settings.Global.ANIMATOR_DURATION_SCALE);
+ Settings.Global.ANIMATOR_DURATION_SCALE));
delayTimeMs *= scale;
} catch (Settings.SettingNotFoundException e) {
// do nothing
diff --git a/core/res/res/drawable/ic_sd_card_48dp.xml b/core/res/res/drawable/ic_sd_card_48dp.xml
index 90bab47..10fd120 100644
--- a/core/res/res/drawable/ic_sd_card_48dp.xml
+++ b/core/res/res/drawable/ic_sd_card_48dp.xml
@@ -19,6 +19,6 @@
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
- android:fillColor="#FF000000"
+ android:fillColor="?android:attr/colorAccent"
android:pathData="M36 4H20L8.04 16 8 40c0 2.2 1.8 4 4 4h24c2.2 0 4,-1.8 4,-4V8c0,-2.2,-1.8,-4,-4,-4zM24 16h-4V8h4v8zm6 0h-4V8h4v8zm6 0h-4V8h4v8z"/>
</vector>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 05b9c8a..1af80a5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5899,4 +5899,10 @@
<!-- The number of tasks to scan to get the visibility of Home -->
<integer name="config_maxScanTasksForHomeVisibility">10</integer>
+
+ <!-- Device state that corresponds to rear display mode, feature provided
+ through Jetpack WindowManager
+ TODO(b/236022708) Move rear display state to device state config file
+ -->
+ <integer name="config_deviceStateRearDisplay">-1</integer>
</resources>
diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml
index e9b42d3..78ec145 100644
--- a/core/res/res/values/locale_config.xml
+++ b/core/res/res/values/locale_config.xml
@@ -23,7 +23,7 @@
<item>ak-GH</item> <!-- Akan (Ghana) -->
<item>am-ET</item> <!-- Amharic (Ethiopia) -->
<item>ar-AE</item> <!-- Arabic (United Arab Emirates) -->
- <item>ar-AE-u-nu-latn</item> <!-- Arabic (United Arab Emirates, Western Digits) -->
+ <item>ar-AE-u-nu-arab</item> <!-- Arabic (United Arab Emirates, Arabic Digits) -->
<item>ar-BH</item> <!-- Arabic (Bahrain) -->
<item>ar-BH-u-nu-latn</item> <!-- Arabic (Bahrain, Western Digits) -->
<item>ar-DJ</item> <!-- Arabic (Djibouti) -->
@@ -190,6 +190,7 @@
<item>en-MS</item> <!-- English (Montserrat) -->
<item>en-MT</item> <!-- English (Malta) -->
<item>en-MU</item> <!-- English (Mauritius) -->
+ <item>en-MV</item> <!-- English (Maldives) -->
<item>en-MW</item> <!-- English (Malawi) -->
<item>en-MY</item> <!-- English (Malaysia) -->
<item>en-NA</item> <!-- English (Namibia) -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e3b7100..17f0fd0 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3974,7 +3974,7 @@
<string name="ext_media_new_notification_message" product="automotive">You may need to reformat the device. Tap to eject.</string>
<!-- Notification body when external media is ready for use [CHAR LIMIT=NONE] -->
- <string name="ext_media_ready_notification_message">For transferring photos and media</string>
+ <string name="ext_media_ready_notification_message">For storing photos, videos, music and more</string>
<!-- TV specific notification body when external media is ready for use [CHAR LIMIT=75] -->
<string name="ext_media_ready_notification_message" product="tv">Browse media files</string>
@@ -3990,11 +3990,11 @@
<string name="ext_media_unmountable_notification_message" product="automotive">You may need to reformat the device. Tap to eject.</string>
<!-- Notification title when external media is unsupported [CHAR LIMIT=30] -->
- <string name="ext_media_unsupported_notification_title">Unsupported <xliff:g id="name" example="SD card">%s</xliff:g></string>
+ <string name="ext_media_unsupported_notification_title"><xliff:g id="name" example="SD card">%s</xliff:g> detected </string>
<!-- Automotive specific notification title when external media is unsupported [CHAR LIMIT=30] -->
<string name="ext_media_unsupported_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
<!-- Notification body when external media is unsupported [CHAR LIMIT=NONE] -->
- <string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Tap to set up in a supported format.</string>
+ <string name="ext_media_unsupported_notification_message">Tap to set up .</string>
<!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=75] -->
<string name="ext_media_unsupported_notification_message" product="tv">Select to set up <xliff:g id="name" example="SD card">%s</xliff:g> in a supported format.</string>
<!-- Automotive specific notification body when external media is unsupported [CHAR LIMIT=NONE] -->
@@ -4025,7 +4025,7 @@
<!-- Notification action to transfer media [CHAR LIMIT=40] -->
<string name="ext_media_seamless_action">Switch output</string>
- <!-- Notification title when external media is missing [CHAR LIMIT=30] -->
+ <!-- Notification title when adoptable storage media is ejected [CHAR LIMIT=30] -->
<string name="ext_media_missing_title"><xliff:g id="name" example="SD card">%s</xliff:g> missing</string>
<!-- Notification body when external media is missing [CHAR LIMIT=30] -->
<string name="ext_media_missing_message">Insert device again</string>
@@ -6323,6 +6323,8 @@
<string name="vdm_camera_access_denied" product="default">Can’t access the phone’s camera from your <xliff:g id="device" example="Chromebook">%1$s</xliff:g></string>
<!-- Error message indicating the camera cannot be accessed when running on a virtual device. [CHAR LIMIT=NONE] -->
<string name="vdm_camera_access_denied" product="tablet">Can’t access the tablet’s camera from your <xliff:g id="device" example="Chromebook">%1$s</xliff:g></string>
+ <!-- Error message indicating the user cannot access secure content when running on a virtual device. [CHAR LIMIT=NONE] -->
+ <string name="vdm_secure_window">This can’t be accessed while streaming. Try on your phone instead.</string>
<!-- Title for preference of the system default locale. [CHAR LIMIT=50]-->
<string name="system_locale_title">System default</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 205681c..c098aca 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4795,6 +4795,7 @@
<!-- For VirtualDeviceManager -->
<java-symbol type="string" name="vdm_camera_access_denied" />
+ <java-symbol type="string" name="vdm_secure_window" />
<java-symbol type="color" name="camera_privacy_light_day"/>
<java-symbol type="color" name="camera_privacy_light_night"/>
@@ -4821,6 +4822,7 @@
<java-symbol type="drawable" name="ic_swap_horiz" />
<java-symbol type="array" name="config_deviceStatesAvailableForAppRequests" />
<java-symbol type="array" name="config_serviceStateLocationAllowedPackages" />
+ <java-symbol type="integer" name="config_deviceStateRearDisplay"/>
<!-- For app language picker -->
<java-symbol type="string" name="system_locale_title" />
diff --git a/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
new file mode 100644
index 0000000..2a3da05
--- /dev/null
+++ b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NotificationChannelGroupTest {
+ private final String CLASS = "android.app.NotificationChannelGroup";
+
+ @Test
+ public void testLongStringFields() {
+ NotificationChannelGroup group = new NotificationChannelGroup("my_group_01", "groupName");
+
+ try {
+ String longString = Strings.repeat("A", 65536);
+ Field mName = Class.forName(CLASS).getDeclaredField("mName");
+ mName.setAccessible(true);
+ mName.set(group, longString);
+ Field mId = Class.forName(CLASS).getDeclaredField("mId");
+ mId.setAccessible(true);
+ mId.set(group, longString);
+ Field mDescription = Class.forName(CLASS).getDeclaredField("mDescription");
+ mDescription.setAccessible(true);
+ mDescription.set(group, longString);
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ Parcel parcel = Parcel.obtain();
+ group.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannelGroup fromParcel =
+ NotificationChannelGroup.CREATOR.createFromParcel(parcel);
+ assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getId().length());
+ assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getName().length());
+ assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH,
+ fromParcel.getDescription().length());
+ }
+}
diff --git a/core/tests/coretests/src/android/app/NotificationChannelTest.java b/core/tests/coretests/src/android/app/NotificationChannelTest.java
new file mode 100644
index 0000000..647bfe8
--- /dev/null
+++ b/core/tests/coretests/src/android/app/NotificationChannelTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.net.Uri;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NotificationChannelTest {
+ private final String CLASS = "android.app.NotificationChannel";
+
+ @Test
+ public void testLongStringFields() {
+ NotificationChannel channel = new NotificationChannel("id", "name", 3);
+
+ try {
+ String longString = Strings.repeat("A", 65536);
+ Field mName = Class.forName(CLASS).getDeclaredField("mName");
+ mName.setAccessible(true);
+ mName.set(channel, longString);
+ Field mId = Class.forName(CLASS).getDeclaredField("mId");
+ mId.setAccessible(true);
+ mId.set(channel, longString);
+ Field mDesc = Class.forName(CLASS).getDeclaredField("mDesc");
+ mDesc.setAccessible(true);
+ mDesc.set(channel, longString);
+ Field mParentId = Class.forName(CLASS).getDeclaredField("mParentId");
+ mParentId.setAccessible(true);
+ mParentId.set(channel, longString);
+ Field mGroup = Class.forName(CLASS).getDeclaredField("mGroup");
+ mGroup.setAccessible(true);
+ mGroup.set(channel, longString);
+ Field mConversationId = Class.forName(CLASS).getDeclaredField("mConversationId");
+ mConversationId.setAccessible(true);
+ mConversationId.set(channel, longString);
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ Parcel parcel = Parcel.obtain();
+ channel.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannel fromParcel = NotificationChannel.CREATOR.createFromParcel(parcel);
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH, fromParcel.getId().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH, fromParcel.getName().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getDescription().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getParentChannelId().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getGroup().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getConversationId().length());
+ }
+
+ @Test
+ public void testLongAlertFields() {
+ NotificationChannel channel = new NotificationChannel("id", "name", 3);
+
+ channel.setSound(Uri.parse("content://" + Strings.repeat("A",65536)),
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channel.setVibrationPattern(new long[65550/2]);
+
+ Parcel parcel = Parcel.obtain();
+ channel.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannel fromParcel = NotificationChannel.CREATOR.createFromParcel(parcel);
+ assertEquals(NotificationChannel.MAX_VIBRATION_LENGTH,
+ fromParcel.getVibrationPattern().length);
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getSound().toString().length());
+ }
+}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index ed6a649..6e59b83 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -236,6 +236,21 @@
}
@Test
+ public void testSystemDrivenInsetsAnimationLoggingListener_onReady() {
+ prepareControls();
+ // only the original thread that created view hierarchy can touch its views
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ WindowInsetsAnimationControlListener loggingListener =
+ mock(WindowInsetsAnimationControlListener.class);
+ mController.setSystemDrivenInsetsAnimationLoggingListener(loggingListener);
+ mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained(true);
+ // since there is no focused view, forcefully make IME visible.
+ mController.show(Type.ime(), true /* fromIme */);
+ verify(loggingListener).onReady(notNull(), anyInt());
+ });
+ }
+
+ @Test
public void testAnimationEndState() {
InsetsSourceControl[] controls = prepareControls();
InsetsSourceControl navBar = controls[0];
diff --git a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
index 03c8b1b..690b3587 100644
--- a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
@@ -213,6 +213,25 @@
}
@Test
+ public void testSystemDrivenInsetsAnimationLoggingListener() {
+ WindowInsetsAnimationControlListener listener =
+ mock(WindowInsetsAnimationControlListener.class);
+ mPendingInsetsController.setSystemDrivenInsetsAnimationLoggingListener(listener);
+ mPendingInsetsController.replayAndAttach(mReplayedController);
+ verify(mReplayedController).setSystemDrivenInsetsAnimationLoggingListener(eq(listener));
+ }
+
+ @Test
+ public void testSystemDrivenInsetsAnimationLoggingListener_direct() {
+ mPendingInsetsController.replayAndAttach(mReplayedController);
+ WindowInsetsAnimationControlListener listener =
+ mock(WindowInsetsAnimationControlListener.class);
+ mPendingInsetsController.setSystemDrivenInsetsAnimationLoggingListener(listener);
+ verify(mReplayedController).setSystemDrivenInsetsAnimationLoggingListener(
+ eq(listener));
+ }
+
+ @Test
public void testDetachReattach() {
mPendingInsetsController.show(systemBars());
mPendingInsetsController.setSystemBarsBehavior(BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index bdf703c..7e9c418 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -20,11 +20,14 @@
import android.content.Context;
import androidx.annotation.NonNull;
+import androidx.window.extensions.area.WindowAreaComponent;
+import androidx.window.extensions.area.WindowAreaComponentImpl;
import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
import androidx.window.extensions.embedding.SplitController;
import androidx.window.extensions.layout.WindowLayoutComponent;
import androidx.window.extensions.layout.WindowLayoutComponentImpl;
+
/**
* The reference implementation of {@link WindowExtensions} that implements the initial API version.
*/
@@ -33,10 +36,12 @@
private final Object mLock = new Object();
private volatile WindowLayoutComponent mWindowLayoutComponent;
private volatile SplitController mSplitController;
+ private volatile WindowAreaComponent mWindowAreaComponent;
+ // TODO(b/241126279) Introduce constants to better version functionality
@Override
public int getVendorApiLevel() {
- return 1;
+ return 2;
}
/**
@@ -75,4 +80,23 @@
}
return mSplitController;
}
+
+ /**
+ * Returns a reference implementation of {@link WindowAreaComponent} if available,
+ * {@code null} otherwise. The implementation must match the API level reported in
+ * {@link WindowExtensions#getWindowAreaComponent()}.
+ * @return {@link WindowAreaComponent} OEM implementation.
+ */
+ public WindowAreaComponent getWindowAreaComponent() {
+ if (mWindowAreaComponent == null) {
+ synchronized (mLock) {
+ if (mWindowAreaComponent == null) {
+ Context context = ActivityThread.currentApplication();
+ mWindowAreaComponent =
+ new WindowAreaComponentImpl(context);
+ }
+ }
+ }
+ return mWindowAreaComponent;
+ }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
new file mode 100644
index 0000000..3adae70
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.area;
+
+import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
+
+import android.app.Activity;
+import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.DeviceStateRequest;
+import android.util.ArraySet;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Reference implementation of androidx.window.extensions.area OEM interface for use with
+ * WindowManager Jetpack.
+ *
+ * This component currently supports Rear Display mode with the ability to add and remove
+ * status listeners for this mode.
+ *
+ * The public methods in this class are thread-safe.
+ **/
+public class WindowAreaComponentImpl implements WindowAreaComponent,
+ DeviceStateManager.DeviceStateCallback {
+
+ private final Object mLock = new Object();
+
+ private final DeviceStateManager mDeviceStateManager;
+ private final Executor mExecutor;
+
+ @GuardedBy("mLock")
+ private final ArraySet<Consumer<Integer>> mRearDisplayStatusListeners = new ArraySet<>();
+ private final int mRearDisplayState;
+ @WindowAreaSessionState
+ private int mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_INACTIVE;
+
+ @GuardedBy("mLock")
+ private int mCurrentDeviceState = INVALID_DEVICE_STATE;
+ @GuardedBy("mLock")
+ private int mCurrentDeviceBaseState = INVALID_DEVICE_STATE;
+ @GuardedBy("mLock")
+ private DeviceStateRequest mDeviceStateRequest;
+
+ public WindowAreaComponentImpl(@NonNull Context context) {
+ mDeviceStateManager = context.getSystemService(DeviceStateManager.class);
+ mExecutor = context.getMainExecutor();
+
+ // TODO(b/236022708) Move rear display state to device state config file
+ mRearDisplayState = context.getResources().getInteger(
+ R.integer.config_deviceStateRearDisplay);
+
+ mDeviceStateManager.registerCallback(mExecutor, this);
+ }
+
+ /**
+ * Adds a listener interested in receiving updates on the RearDisplayStatus
+ * of the device. Because this is being called from the OEM provided
+ * extensions, we will post the result of the listener on the executor
+ * provided by the developer at the initial call site.
+ *
+ * Depending on the initial state of the device, we will return either
+ * {@link WindowAreaComponent#STATUS_AVAILABLE} or
+ * {@link WindowAreaComponent#STATUS_UNAVAILABLE} if the feature is supported or not in that
+ * state respectively. When the rear display feature is triggered, we update the status to be
+ * {@link WindowAreaComponent#STATUS_UNAVAILABLE}. TODO(b/240727590) Prefix with AREA_
+ *
+ * TODO(b/239833099) Add a STATUS_ACTIVE option to let apps know if a feature is currently
+ * enabled.
+ *
+ * @param consumer {@link Consumer} interested in receiving updates to the status of
+ * rear display mode.
+ */
+ public void addRearDisplayStatusListener(
+ @NonNull Consumer<@WindowAreaStatus Integer> consumer) {
+ synchronized (mLock) {
+ mRearDisplayStatusListeners.add(consumer);
+
+ // If current device state is still invalid, we haven't gotten our initial value yet
+ if (mCurrentDeviceState == INVALID_DEVICE_STATE) {
+ return;
+ }
+ consumer.accept(getCurrentStatus());
+ }
+ }
+
+ /**
+ * Removes a listener no longer interested in receiving updates.
+ * @param consumer no longer interested in receiving updates to RearDisplayStatus
+ */
+ public void removeRearDisplayStatusListener(
+ @NonNull Consumer<@WindowAreaStatus Integer> consumer) {
+ synchronized (mLock) {
+ mRearDisplayStatusListeners.remove(consumer);
+ }
+ }
+
+ /**
+ * Creates and starts a rear display session and provides updates to the
+ * callback provided. Because this is being called from the OEM provided
+ * extensions, we will post the result of the listener on the executor
+ * provided by the developer at the initial call site.
+ *
+ * When we enable rear display mode, we submit a request to {@link DeviceStateManager}
+ * to override the device state to the state that corresponds to RearDisplay
+ * mode. When the {@link DeviceStateRequest} is activated, we let the
+ * consumer know that the session is active by sending
+ * {@link WindowAreaComponent#SESSION_STATE_ACTIVE}.
+ *
+ * @param activity to provide updates to the client on
+ * the status of the Session
+ * @param rearDisplaySessionCallback to provide updates to the client on
+ * the status of the Session
+ */
+ public void startRearDisplaySession(@NonNull Activity activity,
+ @NonNull Consumer<@WindowAreaSessionState Integer> rearDisplaySessionCallback) {
+ synchronized (mLock) {
+ if (mDeviceStateRequest != null) {
+ // Rear display session is already active
+ throw new IllegalStateException(
+ "Unable to start new rear display session as one is already active");
+ }
+ mDeviceStateRequest = DeviceStateRequest.newBuilder(mRearDisplayState).build();
+ mDeviceStateManager.requestState(
+ mDeviceStateRequest,
+ mExecutor,
+ new DeviceStateRequestCallbackAdapter(rearDisplaySessionCallback)
+ );
+ }
+ }
+
+ /**
+ * Ends the current rear display session and provides updates to the
+ * callback provided. Because this is being called from the OEM provided
+ * extensions, we will post the result of the listener on the executor
+ * provided by the developer.
+ */
+ public void endRearDisplaySession() {
+ synchronized (mLock) {
+ if (mDeviceStateRequest != null || isRearDisplayActive()) {
+ mDeviceStateRequest = null;
+ mDeviceStateManager.cancelStateRequest();
+ } else {
+ throw new IllegalStateException(
+ "Unable to cancel a rear display session as there is no active session");
+ }
+ }
+ }
+
+ @Override
+ public void onBaseStateChanged(int state) {
+ synchronized (mLock) {
+ mCurrentDeviceBaseState = state;
+ if (state == mCurrentDeviceState) {
+ updateStatusConsumers(getCurrentStatus());
+ }
+ }
+ }
+
+ @Override
+ public void onStateChanged(int state) {
+ synchronized (mLock) {
+ mCurrentDeviceState = state;
+ updateStatusConsumers(getCurrentStatus());
+ }
+ }
+
+ @GuardedBy("mLock")
+ private int getCurrentStatus() {
+ if (mRearDisplaySessionStatus == WindowAreaComponent.SESSION_STATE_ACTIVE
+ || isRearDisplayActive()) {
+ return WindowAreaComponent.STATUS_UNAVAILABLE;
+ }
+ return WindowAreaComponent.STATUS_AVAILABLE;
+ }
+
+ /**
+ * Helper method to determine if a rear display session is currently active by checking
+ * if the current device configuration matches that of rear display. This would be true
+ * if there is a device override currently active (base state != current state) and the current
+ * state is that which corresponds to {@code mRearDisplayState}
+ * @return {@code true} if the device is in rear display mode and {@code false} if not
+ */
+ @GuardedBy("mLock")
+ private boolean isRearDisplayActive() {
+ return (mCurrentDeviceState != mCurrentDeviceBaseState) && (mCurrentDeviceState
+ == mRearDisplayState);
+ }
+
+ @GuardedBy("mLock")
+ private void updateStatusConsumers(@WindowAreaStatus int windowAreaStatus) {
+ synchronized (mLock) {
+ for (int i = 0; i < mRearDisplayStatusListeners.size(); i++) {
+ mRearDisplayStatusListeners.valueAt(i).accept(windowAreaStatus);
+ }
+ }
+ }
+
+ /**
+ * Callback for the {@link DeviceStateRequest} to be notified of when the request has been
+ * activated or cancelled. This callback provides information to the client library
+ * on the status of the RearDisplay session through {@code mRearDisplaySessionCallback}
+ */
+ private class DeviceStateRequestCallbackAdapter implements DeviceStateRequest.Callback {
+
+ private final Consumer<Integer> mRearDisplaySessionCallback;
+
+ DeviceStateRequestCallbackAdapter(@NonNull Consumer<Integer> callback) {
+ mRearDisplaySessionCallback = callback;
+ }
+
+ @Override
+ public void onRequestActivated(@NonNull DeviceStateRequest request) {
+ synchronized (mLock) {
+ if (request.equals(mDeviceStateRequest)) {
+ mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_ACTIVE;
+ mRearDisplaySessionCallback.accept(mRearDisplaySessionStatus);
+ updateStatusConsumers(getCurrentStatus());
+ }
+ }
+ }
+
+ @Override
+ public void onRequestCanceled(DeviceStateRequest request) {
+ synchronized (mLock) {
+ if (request.equals(mDeviceStateRequest)) {
+ mDeviceStateRequest = null;
+ }
+ mRearDisplaySessionStatus = WindowAreaComponent.SESSION_STATE_INACTIVE;
+ mRearDisplaySessionCallback.accept(mRearDisplaySessionStatus);
+ updateStatusConsumers(getCurrentStatus());
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index d42fca2..1335e5e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -51,28 +51,37 @@
@VisibleForTesting
final Map<IBinder, TaskFragmentInfo> mFragmentInfos = new ArrayMap<>();
+ @NonNull
private final TaskFragmentCallback mCallback;
+
@VisibleForTesting
+ @Nullable
TaskFragmentAnimationController mAnimationController;
/**
* Callback that notifies the controller about changes to task fragments.
*/
interface TaskFragmentCallback {
- void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo);
- void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo);
- void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo);
- void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig);
- void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
- @NonNull IBinder activityToken);
- void onTaskFragmentError(@Nullable TaskFragmentInfo taskFragmentInfo, int opType);
+ void onTaskFragmentAppeared(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo);
+ void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo);
+ void onTaskFragmentVanished(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo);
+ void onTaskFragmentParentInfoChanged(@NonNull WindowContainerTransaction wct,
+ int taskId, @NonNull Configuration parentConfig);
+ void onActivityReparentedToTask(@NonNull WindowContainerTransaction wct,
+ int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken);
+ void onTaskFragmentError(@NonNull WindowContainerTransaction wct,
+ @Nullable TaskFragmentInfo taskFragmentInfo, int opType);
}
/**
* @param executor callbacks from WM Core are posted on this executor. It should be tied to the
* UI thread that all other calls into methods of this class are also on.
*/
- JetpackTaskFragmentOrganizer(@NonNull Executor executor, TaskFragmentCallback callback) {
+ JetpackTaskFragmentOrganizer(@NonNull Executor executor,
+ @NonNull TaskFragmentCallback callback) {
super(executor);
mCallback = callback;
}
@@ -147,41 +156,31 @@
* @param wct WindowContainerTransaction in which the task fragment should be resized.
* @param fragmentToken token of an existing TaskFragment.
*/
- void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
+ void expandTaskFragment(@NonNull WindowContainerTransaction wct,
+ @NonNull IBinder fragmentToken) {
resizeTaskFragment(wct, fragmentToken, new Rect());
setAdjacentTaskFragments(wct, fragmentToken, null /* secondary */, null /* splitRule */);
updateWindowingMode(wct, fragmentToken, WINDOWING_MODE_UNDEFINED);
}
/**
- * Expands an existing TaskFragment to fill parent.
- * @param fragmentToken token of an existing TaskFragment.
- */
- void expandTaskFragment(IBinder fragmentToken) {
- WindowContainerTransaction wct = new WindowContainerTransaction();
- expandTaskFragment(wct, fragmentToken);
- applyTransaction(wct);
- }
-
- /**
* Expands an Activity to fill parent by moving it to a new TaskFragment.
* @param fragmentToken token to create new TaskFragment with.
* @param activity activity to move to the fill-parent TaskFragment.
*/
- void expandActivity(IBinder fragmentToken, Activity activity) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
+ void expandActivity(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
+ @NonNull Activity activity) {
createTaskFragmentAndReparentActivity(
wct, fragmentToken, activity.getActivityToken(), new Rect(),
WINDOWING_MODE_UNDEFINED, activity);
- applyTransaction(wct);
}
/**
* @param ownerToken The token of the activity that creates this task fragment. It does not
* have to be a child of this task fragment, but must belong to the same task.
*/
- void createTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken,
- IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) {
+ void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
+ @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) {
final TaskFragmentCreationParams fragmentOptions =
createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
wct.createTaskFragment(fragmentOptions);
@@ -191,9 +190,9 @@
* @param ownerToken The token of the activity that creates this task fragment. It does not
* have to be a child of this task fragment, but must belong to the same task.
*/
- private void createTaskFragmentAndReparentActivity(
- WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
- @NonNull Rect bounds, @WindowingMode int windowingMode, Activity activity) {
+ private void createTaskFragmentAndReparentActivity(@NonNull WindowContainerTransaction wct,
+ @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds,
+ @WindowingMode int windowingMode, @NonNull Activity activity) {
createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode);
wct.reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken());
}
@@ -202,9 +201,9 @@
* @param ownerToken The token of the activity that creates this task fragment. It does not
* have to be a child of this task fragment, but must belong to the same task.
*/
- private void createTaskFragmentAndStartActivity(
- WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
- @NonNull Rect bounds, @WindowingMode int windowingMode, Intent activityIntent,
+ private void createTaskFragmentAndStartActivity(@NonNull WindowContainerTransaction wct,
+ @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds,
+ @WindowingMode int windowingMode, @NonNull Intent activityIntent,
@Nullable Bundle activityOptions) {
createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode);
wct.startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent, activityOptions);
@@ -225,8 +224,8 @@
wct.setAdjacentTaskFragments(primary, secondary, adjacentParams);
}
- TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken,
- Rect bounds, @WindowingMode int windowingMode) {
+ TaskFragmentCreationParams createFragmentOptions(@NonNull IBinder fragmentToken,
+ @NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) {
if (mFragmentInfos.containsKey(fragmentToken)) {
throw new IllegalArgumentException(
"There is an existing TaskFragment with fragmentToken=" + fragmentToken);
@@ -241,7 +240,7 @@
.build();
}
- void resizeTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken,
+ void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
@Nullable Rect bounds) {
if (!mFragmentInfos.containsKey(fragmentToken)) {
throw new IllegalArgumentException(
@@ -253,8 +252,8 @@
wct.setBounds(mFragmentInfos.get(fragmentToken).getToken(), bounds);
}
- void updateWindowingMode(WindowContainerTransaction wct, IBinder fragmentToken,
- @WindowingMode int windowingMode) {
+ void updateWindowingMode(@NonNull WindowContainerTransaction wct,
+ @NonNull IBinder fragmentToken, @WindowingMode int windowingMode) {
if (!mFragmentInfos.containsKey(fragmentToken)) {
throw new IllegalArgumentException(
"Can't find an existing TaskFragment with fragmentToken=" + fragmentToken);
@@ -262,7 +261,8 @@
wct.setWindowingMode(mFragmentInfos.get(fragmentToken).getToken(), windowingMode);
}
- void deleteTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
+ void deleteTaskFragment(@NonNull WindowContainerTransaction wct,
+ @NonNull IBinder fragmentToken) {
if (!mFragmentInfos.containsKey(fragmentToken)) {
throw new IllegalArgumentException(
"Can't find an existing TaskFragment with fragmentToken=" + fragmentToken);
@@ -271,60 +271,49 @@
}
@Override
- public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ public void onTaskFragmentAppeared(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo) {
final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
mFragmentInfos.put(fragmentToken, taskFragmentInfo);
-
- if (mCallback != null) {
- mCallback.onTaskFragmentAppeared(taskFragmentInfo);
- }
+ mCallback.onTaskFragmentAppeared(wct, taskFragmentInfo);
}
@Override
- public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ public void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo) {
final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
mFragmentInfos.put(fragmentToken, taskFragmentInfo);
-
- if (mCallback != null) {
- mCallback.onTaskFragmentInfoChanged(taskFragmentInfo);
- }
+ mCallback.onTaskFragmentInfoChanged(wct, taskFragmentInfo);
}
@Override
- public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ public void onTaskFragmentVanished(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo) {
mFragmentInfos.remove(taskFragmentInfo.getFragmentToken());
-
- if (mCallback != null) {
- mCallback.onTaskFragmentVanished(taskFragmentInfo);
- }
+ mCallback.onTaskFragmentVanished(wct, taskFragmentInfo);
}
@Override
- public void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig) {
- if (mCallback != null) {
- mCallback.onTaskFragmentParentInfoChanged(taskId, parentConfig);
- }
+ public void onTaskFragmentParentInfoChanged(@NonNull WindowContainerTransaction wct,
+ int taskId, @NonNull Configuration parentConfig) {
+ mCallback.onTaskFragmentParentInfoChanged(wct, taskId, parentConfig);
}
@Override
- public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
- @NonNull IBinder activityToken) {
- if (mCallback != null) {
- mCallback.onActivityReparentToTask(taskId, activityIntent, activityToken);
- }
+ public void onActivityReparentedToTask(@NonNull WindowContainerTransaction wct,
+ int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken) {
+ mCallback.onActivityReparentedToTask(wct, taskId, activityIntent, activityToken);
}
@Override
- public void onTaskFragmentError(@NonNull IBinder errorCallbackToken,
+ public void onTaskFragmentError(@NonNull WindowContainerTransaction wct,
+ @NonNull IBinder errorCallbackToken,
@Nullable TaskFragmentInfo taskFragmentInfo,
int opType, @NonNull Throwable exception) {
if (taskFragmentInfo != null) {
final IBinder fragmentToken = taskFragmentInfo.getFragmentToken();
mFragmentInfos.put(fragmentToken, taskFragmentInfo);
}
-
- if (mCallback != null) {
- mCallback.onTaskFragmentError(taskFragmentInfo, opType);
- }
+ mCallback.onTaskFragmentError(wct, taskFragmentInfo, opType);
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index f09a910..c8ac0fc 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -16,17 +16,21 @@
package androidx.window.extensions.embedding;
-import android.annotation.NonNull;
import android.app.Activity;
import android.util.Pair;
import android.util.Size;
+import androidx.annotation.NonNull;
+
/**
* Client-side descriptor of a split that holds two containers.
*/
class SplitContainer {
+ @NonNull
private final TaskFragmentContainer mPrimaryContainer;
+ @NonNull
private final TaskFragmentContainer mSecondaryContainer;
+ @NonNull
private final SplitRule mSplitRule;
SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index dad0739..0597809f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -145,35 +145,36 @@
}
@Override
- public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ public void onTaskFragmentAppeared(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo) {
synchronized (mLock) {
TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken());
if (container == null) {
return;
}
- container.setInfo(taskFragmentInfo);
+ container.setInfo(wct, taskFragmentInfo);
if (container.isFinished()) {
- mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
+ mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
} else {
// Update with the latest Task configuration.
- mPresenter.updateContainer(container);
+ updateContainer(wct, container);
}
updateCallbackIfNecessary();
}
}
@Override
- public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ public void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo) {
synchronized (mLock) {
TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken());
if (container == null) {
return;
}
- final WindowContainerTransaction wct = new WindowContainerTransaction();
final boolean wasInPip = isInPictureInPicture(container);
- container.setInfo(taskFragmentInfo);
+ container.setInfo(wct, taskFragmentInfo);
final boolean isInPip = isInPictureInPicture(container);
// Check if there are no running activities - consider the container empty if there are
// no non-finishing activities left.
@@ -183,15 +184,15 @@
// Instead, the original split should be cleanup, and the dependent may be
// expanded to fullscreen.
cleanupForEnterPip(wct, container);
- mPresenter.cleanupContainer(container, false /* shouldFinishDependent */, wct);
+ mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
} else if (taskFragmentInfo.isTaskClearedForReuse()) {
// Do not finish the dependents if this TaskFragment was cleared due to
// launching activity in the Task.
- mPresenter.cleanupContainer(container, false /* shouldFinishDependent */, wct);
+ mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
} else if (!container.isWaitingActivityAppear()) {
// Do not finish the container before the expected activity appear until
// timeout.
- mPresenter.cleanupContainer(container, true /* shouldFinishDependent */, wct);
+ mPresenter.cleanupContainer(wct, container, true /* shouldFinishDependent */);
}
} else if (wasInPip && isInPip) {
// No update until exit PIP.
@@ -208,13 +209,13 @@
// needed.
updateContainer(wct, container);
}
- mPresenter.applyTransaction(wct);
updateCallbackIfNecessary();
}
}
@Override
- public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ public void onTaskFragmentVanished(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentInfo taskFragmentInfo) {
synchronized (mLock) {
final TaskFragmentContainer container = getContainer(
taskFragmentInfo.getFragmentToken());
@@ -225,9 +226,7 @@
final TaskFragmentContainer newTopContainer = getTopActiveContainer(
container.getTaskId());
if (newTopContainer != null) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
updateContainer(wct, newTopContainer);
- mPresenter.applyTransaction(wct);
}
updateCallbackIfNecessary();
}
@@ -236,7 +235,8 @@
}
@Override
- public void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig) {
+ public void onTaskFragmentParentInfoChanged(@NonNull WindowContainerTransaction wct,
+ int taskId, @NonNull Configuration parentConfig) {
synchronized (mLock) {
onTaskConfigurationChanged(taskId, parentConfig);
if (isInPictureInPicture(parentConfig)) {
@@ -256,7 +256,7 @@
final TaskFragmentContainer container = containers.get(i);
// Wait until onTaskFragmentAppeared to update new container.
if (!container.isFinished() && !container.isWaitingActivityAppear()) {
- mPresenter.updateContainer(container);
+ updateContainer(wct, container);
}
}
updateCallbackIfNecessary();
@@ -264,7 +264,8 @@
}
@Override
- public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
+ public void onActivityReparentedToTask(@NonNull WindowContainerTransaction wct,
+ int taskId, @NonNull Intent activityIntent,
@NonNull IBinder activityToken) {
synchronized (mLock) {
// If the activity belongs to the current app process, we treat it as a new activity
@@ -275,10 +276,10 @@
// launching to top. We allow split as primary for activity reparent because the
// activity may be split as primary before it is reparented out. In that case, we
// want to show it as primary again when it is reparented back.
- if (!resolveActivityToContainer(activity, true /* isOnReparent */)) {
+ if (!resolveActivityToContainer(wct, activity, true /* isOnReparent */)) {
// When there is no embedding rule matched, try to place it in the top container
// like a normal launch.
- placeActivityInTopContainer(activity);
+ placeActivityInTopContainer(wct, activity);
}
updateCallbackIfNecessary();
return;
@@ -293,7 +294,6 @@
// If the activity belongs to a different app process, we treat it as starting new
// intent, since both actions might result in a new activity that should appear in an
// organized TaskFragment.
- final WindowContainerTransaction wct = new WindowContainerTransaction();
TaskFragmentContainer targetContainer = resolveStartActivityIntent(wct, taskId,
activityIntent, null /* launchingActivity */);
if (targetContainer == null) {
@@ -306,14 +306,14 @@
}
wct.reparentActivityToTaskFragment(targetContainer.getTaskFragmentToken(),
activityToken);
- mPresenter.applyTransaction(wct);
// Because the activity does not belong to the organizer process, we wait until
// onTaskFragmentAppeared to trigger updateCallbackIfNecessary().
}
}
@Override
- public void onTaskFragmentError(@Nullable TaskFragmentInfo taskFragmentInfo, int opType) {
+ public void onTaskFragmentError(@NonNull WindowContainerTransaction wct,
+ @Nullable TaskFragmentInfo taskFragmentInfo, int opType) {
synchronized (mLock) {
switch (opType) {
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
@@ -329,10 +329,11 @@
}
// Update the latest taskFragmentInfo and perform necessary clean-up
- container.setInfo(taskFragmentInfo);
+ container.setInfo(wct, taskFragmentInfo);
container.clearPendingAppearedActivities();
if (container.isEmpty()) {
- mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
+ mPresenter.cleanupContainer(wct, container,
+ false /* shouldFinishDependent */);
}
break;
}
@@ -343,7 +344,7 @@
}
}
- /** Called on receiving {@link #onTaskFragmentVanished(TaskFragmentInfo)} for cleanup. */
+ /** Called on receiving {@link #onTaskFragmentVanished} for cleanup. */
private void cleanupTaskFragment(@NonNull IBinder taskFragmentToken) {
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
final TaskContainer taskContainer = mTaskContainers.valueAt(i);
@@ -422,10 +423,12 @@
}
@VisibleForTesting
- void onActivityCreated(@NonNull Activity launchedActivity) {
+ @GuardedBy("mLock")
+ void onActivityCreated(@NonNull WindowContainerTransaction wct,
+ @NonNull Activity launchedActivity) {
// TODO(b/229680885): we don't support launching into primary yet because we want to always
// launch the new activity on top.
- resolveActivityToContainer(launchedActivity, false /* isOnReparent */);
+ resolveActivityToContainer(wct, launchedActivity, false /* isOnReparent */);
updateCallbackIfNecessary();
}
@@ -440,7 +443,8 @@
*/
@VisibleForTesting
@GuardedBy("mLock")
- boolean resolveActivityToContainer(@NonNull Activity activity, boolean isOnReparent) {
+ boolean resolveActivityToContainer(@NonNull WindowContainerTransaction wct,
+ @NonNull Activity activity, boolean isOnReparent) {
if (isInPictureInPicture(activity) || activity.isFinishing()) {
// We don't embed activity when it is in PIP, or finishing. Return true since we don't
// want any extra handling.
@@ -472,12 +476,12 @@
// 1. Whether the new launched activity should always expand.
if (shouldExpand(activity, null /* intent */)) {
- expandActivity(activity);
+ expandActivity(wct, activity);
return true;
}
// 2. Whether the new launched activity should launch a placeholder.
- if (launchPlaceholderIfNecessary(activity, !isOnReparent)) {
+ if (launchPlaceholderIfNecessary(wct, activity, !isOnReparent)) {
return true;
}
@@ -492,11 +496,11 @@
// Can't find any activity below.
return false;
}
- if (putActivitiesIntoSplitIfNecessary(activityBelow, activity)) {
+ if (putActivitiesIntoSplitIfNecessary(wct, activityBelow, activity)) {
// Have split rule of [ activityBelow | launchedActivity ].
return true;
}
- if (isOnReparent && putActivitiesIntoSplitIfNecessary(activity, activityBelow)) {
+ if (isOnReparent && putActivitiesIntoSplitIfNecessary(wct, activity, activityBelow)) {
// Have split rule of [ launchedActivity | activityBelow].
return true;
}
@@ -519,19 +523,20 @@
// Can't find the top activity on the other split TaskFragment.
return false;
}
- if (putActivitiesIntoSplitIfNecessary(otherTopActivity, activity)) {
+ if (putActivitiesIntoSplitIfNecessary(wct, otherTopActivity, activity)) {
// Have split rule of [ otherTopActivity | launchedActivity ].
return true;
}
// Have split rule of [ launchedActivity | otherTopActivity].
- return isOnReparent && putActivitiesIntoSplitIfNecessary(activity, otherTopActivity);
+ return isOnReparent && putActivitiesIntoSplitIfNecessary(wct, activity, otherTopActivity);
}
/**
* Places the given activity to the top most TaskFragment in the task if there is any.
*/
@VisibleForTesting
- void placeActivityInTopContainer(@NonNull Activity activity) {
+ void placeActivityInTopContainer(@NonNull WindowContainerTransaction wct,
+ @NonNull Activity activity) {
if (getContainerWithActivity(activity) != null) {
// The activity has already been put in a TaskFragment. This is likely to be done by
// the server when the activity is started.
@@ -547,20 +552,20 @@
return;
}
targetContainer.addPendingAppearedActivity(activity);
- final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.reparentActivityToTaskFragment(targetContainer.getTaskFragmentToken(),
activity.getActivityToken());
- mPresenter.applyTransaction(wct);
}
/**
* Starts an activity to side of the launchingActivity with the provided split config.
*/
- private void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent,
+ @GuardedBy("mLock")
+ private void startActivityToSide(@NonNull WindowContainerTransaction wct,
+ @NonNull Activity launchingActivity, @NonNull Intent intent,
@Nullable Bundle options, @NonNull SplitRule sideRule,
@Nullable Consumer<Exception> failureCallback, boolean isPlaceholder) {
try {
- mPresenter.startActivityToSide(launchingActivity, intent, options, sideRule,
+ mPresenter.startActivityToSide(wct, launchingActivity, intent, options, sideRule,
isPlaceholder);
} catch (Exception e) {
if (failureCallback != null) {
@@ -573,15 +578,17 @@
* Expands the given activity by either expanding the TaskFragment it is currently in or putting
* it into a new expanded TaskFragment.
*/
- private void expandActivity(@NonNull Activity activity) {
+ @GuardedBy("mLock")
+ private void expandActivity(@NonNull WindowContainerTransaction wct,
+ @NonNull Activity activity) {
final TaskFragmentContainer container = getContainerWithActivity(activity);
if (shouldContainerBeExpanded(container)) {
// Make sure that the existing container is expanded.
- mPresenter.expandTaskFragment(container.getTaskFragmentToken());
+ mPresenter.expandTaskFragment(wct, container.getTaskFragmentToken());
} else {
// Put activity into a new expanded container.
final TaskFragmentContainer newContainer = newContainer(activity, getTaskId(activity));
- mPresenter.expandActivity(newContainer.getTaskFragmentToken(), activity);
+ mPresenter.expandActivity(wct, newContainer.getTaskFragmentToken(), activity);
}
}
@@ -667,8 +674,8 @@
* and returns {@code true}. Otherwise, returns {@code false}.
*/
@GuardedBy("mLock")
- private boolean putActivitiesIntoSplitIfNecessary(@NonNull Activity primaryActivity,
- @NonNull Activity secondaryActivity) {
+ private boolean putActivitiesIntoSplitIfNecessary(@NonNull WindowContainerTransaction wct,
+ @NonNull Activity primaryActivity, @NonNull Activity secondaryActivity) {
final SplitPairRule splitRule = getSplitRule(primaryActivity, secondaryActivity);
if (splitRule == null) {
return false;
@@ -686,23 +693,23 @@
return true;
}
secondaryContainer.addPendingAppearedActivity(secondaryActivity);
- final WindowContainerTransaction wct = new WindowContainerTransaction();
if (mPresenter.expandSplitContainerIfNeeded(wct, splitContainer, primaryActivity,
secondaryActivity, null /* secondaryIntent */)
!= RESULT_EXPAND_FAILED_NO_TF_INFO) {
wct.reparentActivityToTaskFragment(
secondaryContainer.getTaskFragmentToken(),
secondaryActivity.getActivityToken());
- mPresenter.applyTransaction(wct);
return true;
}
}
// Create new split pair.
- mPresenter.createNewSplitContainer(primaryActivity, secondaryActivity, splitRule);
+ mPresenter.createNewSplitContainer(wct, primaryActivity, secondaryActivity, splitRule);
return true;
}
- private void onActivityConfigurationChanged(@NonNull Activity activity) {
+ @GuardedBy("mLock")
+ private void onActivityConfigurationChanged(@NonNull WindowContainerTransaction wct,
+ @NonNull Activity activity) {
if (activity.isFinishing()) {
// Do nothing if the activity is currently finishing.
return;
@@ -721,7 +728,7 @@
}
// Check if activity requires a placeholder
- launchPlaceholderIfNecessary(activity, false /* isOnCreated */);
+ launchPlaceholderIfNecessary(wct, activity, false /* isOnCreated */);
}
@VisibleForTesting
@@ -741,7 +748,22 @@
* creation.
*/
void onTaskFragmentAppearEmptyTimeout(@NonNull TaskFragmentContainer container) {
- mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
+ synchronized (mLock) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ onTaskFragmentAppearEmptyTimeout(wct, container);
+ mPresenter.applyTransaction(wct);
+ }
+ }
+
+ /**
+ * Called when we have been waiting too long for the TaskFragment to become non-empty after
+ * creation.
+ */
+ void onTaskFragmentAppearEmptyTimeout(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentContainer container) {
+ synchronized (mLock) {
+ mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
+ }
}
/**
@@ -971,6 +993,7 @@
}
/** Cleanups all the dependencies when the TaskFragment is entering PIP. */
+ @GuardedBy("mLock")
private void cleanupForEnterPip(@NonNull WindowContainerTransaction wct,
@NonNull TaskFragmentContainer container) {
final TaskContainer taskContainer = container.getTaskContainer();
@@ -1084,9 +1107,10 @@
* Updates the presentation of the container. If the container is part of the split or should
* have a placeholder, it will also update the other part of the split.
*/
+ @GuardedBy("mLock")
void updateContainer(@NonNull WindowContainerTransaction wct,
@NonNull TaskFragmentContainer container) {
- if (launchPlaceholderIfNecessary(container)) {
+ if (launchPlaceholderIfNecessary(wct, container)) {
// Placeholder was launched, the positions will be updated when the activity is added
// to the secondary container.
return;
@@ -1111,7 +1135,7 @@
// Skip position update - one or both containers are finished.
return;
}
- if (dismissPlaceholderIfNecessary(splitContainer)) {
+ if (dismissPlaceholderIfNecessary(wct, splitContainer)) {
// Placeholder was finished, the positions will be updated when its container is emptied
return;
}
@@ -1173,16 +1197,20 @@
/**
* Checks if the container requires a placeholder and launches it if necessary.
*/
- private boolean launchPlaceholderIfNecessary(@NonNull TaskFragmentContainer container) {
+ @GuardedBy("mLock")
+ private boolean launchPlaceholderIfNecessary(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentContainer container) {
final Activity topActivity = container.getTopNonFinishingActivity();
if (topActivity == null) {
return false;
}
- return launchPlaceholderIfNecessary(topActivity, false /* isOnCreated */);
+ return launchPlaceholderIfNecessary(wct, topActivity, false /* isOnCreated */);
}
- boolean launchPlaceholderIfNecessary(@NonNull Activity activity, boolean isOnCreated) {
+ @GuardedBy("mLock")
+ boolean launchPlaceholderIfNecessary(@NonNull WindowContainerTransaction wct,
+ @NonNull Activity activity, boolean isOnCreated) {
if (activity.isFinishing()) {
return false;
}
@@ -1216,7 +1244,7 @@
// TODO(b/190433398): Handle failed request
final Bundle options = getPlaceholderOptions(activity, isOnCreated);
- startActivityToSide(activity, placeholderRule.getPlaceholderIntent(), options,
+ startActivityToSide(wct, activity, placeholderRule.getPlaceholderIntent(), options,
placeholderRule, null /* failureCallback */, true /* isPlaceholder */);
return true;
}
@@ -1243,7 +1271,9 @@
}
@VisibleForTesting
- boolean dismissPlaceholderIfNecessary(@NonNull SplitContainer splitContainer) {
+ @GuardedBy("mLock")
+ boolean dismissPlaceholderIfNecessary(@NonNull WindowContainerTransaction wct,
+ @NonNull SplitContainer splitContainer) {
if (!splitContainer.isPlaceholderContainer()) {
return false;
}
@@ -1257,7 +1287,7 @@
return false;
}
- mPresenter.cleanupContainer(splitContainer.getSecondaryContainer(),
+ mPresenter.cleanupContainer(wct, splitContainer.getSecondaryContainer(),
false /* shouldFinishDependent */);
return true;
}
@@ -1523,7 +1553,8 @@
private final class LifecycleCallbacks extends EmptyLifecycleCallbacksAdapter {
@Override
- public void onActivityPreCreated(Activity activity, Bundle savedInstanceState) {
+ public void onActivityPreCreated(@NonNull Activity activity,
+ @Nullable Bundle savedInstanceState) {
synchronized (mLock) {
final IBinder activityToken = activity.getActivityToken();
final IBinder initialTaskFragmentToken = getInitialTaskFragmentToken(activity);
@@ -1552,25 +1583,30 @@
}
@Override
- public void onActivityPostCreated(Activity activity, Bundle savedInstanceState) {
+ public void onActivityPostCreated(@NonNull Activity activity,
+ @Nullable Bundle savedInstanceState) {
// Calling after Activity#onCreate is complete to allow the app launch something
// first. In case of a configured placeholder activity we want to make sure
// that we don't launch it if an activity itself already requested something to be
// launched to side.
synchronized (mLock) {
- SplitController.this.onActivityCreated(activity);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ SplitController.this.onActivityCreated(wct, activity);
+ mPresenter.applyTransaction(wct);
}
}
@Override
- public void onActivityConfigurationChanged(Activity activity) {
+ public void onActivityConfigurationChanged(@NonNull Activity activity) {
synchronized (mLock) {
- SplitController.this.onActivityConfigurationChanged(activity);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ SplitController.this.onActivityConfigurationChanged(wct, activity);
+ mPresenter.applyTransaction(wct);
}
}
@Override
- public void onActivityPostDestroyed(Activity activity) {
+ public void onActivityPostDestroyed(@NonNull Activity activity) {
synchronized (mLock) {
SplitController.this.onActivityDestroyed(activity);
}
@@ -1582,7 +1618,7 @@
private final Handler mHandler = new Handler(Looper.getMainLooper());
@Override
- public void execute(Runnable r) {
+ public void execute(@NonNull Runnable r) {
mHandler.post(r);
}
}
@@ -1662,7 +1698,7 @@
* If the two rules have the same presentation, we can reuse the same {@link SplitContainer} if
* there is any.
*/
- private static boolean canReuseContainer(SplitRule rule1, SplitRule rule2) {
+ private static boolean canReuseContainer(@NonNull SplitRule rule1, @NonNull SplitRule rule2) {
if (!isContainerReusableRule(rule1) || !isContainerReusableRule(rule2)) {
return false;
}
@@ -1670,7 +1706,8 @@
}
/** Whether the two rules have the same presentation. */
- private static boolean haveSamePresentation(SplitPairRule rule1, SplitPairRule rule2) {
+ private static boolean haveSamePresentation(@NonNull SplitPairRule rule1,
+ @NonNull SplitPairRule rule2) {
// TODO(b/231655482): add util method to do the comparison in SplitPairRule.
return rule1.getSplitRatio() == rule2.getSplitRatio()
&& rule1.getLayoutDirection() == rule2.getLayoutDirection()
@@ -1684,7 +1721,7 @@
* Whether it is ok for other rule to reuse the {@link TaskFragmentContainer} of the given
* rule.
*/
- private static boolean isContainerReusableRule(SplitRule rule) {
+ private static boolean isContainerReusableRule(@NonNull SplitRule rule) {
// We don't expect to reuse the placeholder rule.
if (!(rule instanceof SplitPairRule)) {
return false;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index a89847a..2b069d7 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -102,37 +102,18 @@
private final SplitController mController;
- SplitPresenter(@NonNull Executor executor, SplitController controller) {
+ SplitPresenter(@NonNull Executor executor, @NonNull SplitController controller) {
super(executor, controller);
mController = controller;
registerOrganizer();
}
/**
- * Updates the presentation of the provided container.
- */
- void updateContainer(@NonNull TaskFragmentContainer container) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- mController.updateContainer(wct, container);
- applyTransaction(wct);
- }
-
- /**
* Deletes the specified container and all other associated and dependent containers in the same
* transaction.
*/
- void cleanupContainer(@NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- cleanupContainer(container, shouldFinishDependent, wct);
- applyTransaction(wct);
- }
-
- /**
- * Deletes the specified container and all other associated and dependent containers in the same
- * transaction.
- */
- void cleanupContainer(@NonNull TaskFragmentContainer container, boolean shouldFinishDependent,
- @NonNull WindowContainerTransaction wct) {
+ void cleanupContainer(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
container.finish(shouldFinishDependent, this, wct, mController);
final TaskFragmentContainer newTopContainer = mController.getTopActiveContainer(
@@ -190,10 +171,9 @@
* created and the activity will be re-parented to it.
* @param rule The split rule to be applied to the container.
*/
- void createNewSplitContainer(@NonNull Activity primaryActivity,
- @NonNull Activity secondaryActivity, @NonNull SplitPairRule rule) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
-
+ void createNewSplitContainer(@NonNull WindowContainerTransaction wct,
+ @NonNull Activity primaryActivity, @NonNull Activity secondaryActivity,
+ @NonNull SplitPairRule rule) {
final Rect parentBounds = getParentContainerBounds(primaryActivity);
final Pair<Size, Size> minDimensionsPair = getActivitiesMinDimensionsPair(primaryActivity,
secondaryActivity);
@@ -219,8 +199,6 @@
minDimensionsPair);
mController.registerSplit(wct, primaryContainer, primaryActivity, secondaryContainer, rule);
-
- applyTransaction(wct);
}
/**
@@ -262,7 +240,8 @@
* @param rule The split rule to be applied to the container.
* @param isPlaceholder Whether the launch is a placeholder.
*/
- void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent activityIntent,
+ void startActivityToSide(@NonNull WindowContainerTransaction wct,
+ @NonNull Activity launchingActivity, @NonNull Intent activityIntent,
@Nullable Bundle activityOptions, @NonNull SplitRule rule, boolean isPlaceholder) {
final Rect parentBounds = getParentContainerBounds(launchingActivity);
final Pair<Size, Size> minDimensionsPair = getActivityIntentMinDimensionsPair(
@@ -284,7 +263,6 @@
launchingActivity, taskId);
final int windowingMode = mController.getTaskContainer(taskId)
.getWindowingModeForSplitTaskFragment(primaryRectBounds);
- final WindowContainerTransaction wct = new WindowContainerTransaction();
mController.registerSplit(wct, primaryContainer, launchingActivity, secondaryContainer,
rule);
startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRectBounds,
@@ -294,7 +272,6 @@
// When placeholder is launched in split, we should keep the focus on the primary.
wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken());
}
- applyTransaction(wct);
}
/**
@@ -502,14 +479,14 @@
}
@NonNull
- static Pair<Size, Size> getActivitiesMinDimensionsPair(Activity primaryActivity,
- Activity secondaryActivity) {
+ static Pair<Size, Size> getActivitiesMinDimensionsPair(@NonNull Activity primaryActivity,
+ @NonNull Activity secondaryActivity) {
return new Pair<>(getMinDimensions(primaryActivity), getMinDimensions(secondaryActivity));
}
@NonNull
- static Pair<Size, Size> getActivityIntentMinDimensionsPair(Activity primaryActivity,
- Intent secondaryIntent) {
+ static Pair<Size, Size> getActivityIntentMinDimensionsPair(@NonNull Activity primaryActivity,
+ @NonNull Intent secondaryIntent) {
return new Pair<>(getMinDimensions(primaryActivity), getMinDimensions(secondaryIntent));
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 0ea5603..77e26c0 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -21,8 +21,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.Activity;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
@@ -31,6 +29,9 @@
import android.util.ArraySet;
import android.window.TaskFragmentInfo;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
index f721341..ee2e139 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
@@ -30,6 +30,8 @@
import android.view.RemoteAnimationDefinition;
import android.window.TaskFragmentOrganizer;
+import androidx.annotation.NonNull;
+
import com.android.internal.annotations.VisibleForTesting;
/** Controls the TaskFragment remote animations. */
@@ -45,7 +47,7 @@
/** Task Ids that we have registered for remote animation. */
private final ArraySet<Integer> mRegisterTasks = new ArraySet<>();
- TaskFragmentAnimationController(TaskFragmentOrganizer organizer) {
+ TaskFragmentAnimationController(@NonNull TaskFragmentOrganizer organizer) {
mOrganizer = organizer;
mDefinition = new RemoteAnimationDefinition();
final RemoteAnimationAdapter animationAdapter =
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index c4f3709..8af2d9c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -112,6 +112,7 @@
}
/** Creates the animator given the transition type and windows. */
+ @NonNull
private Animator createAnimator(@WindowManager.TransitionOldType int transit,
@NonNull RemoteAnimationTarget[] targets,
@NonNull IRemoteAnimationFinishedCallback finishedCallback) {
@@ -161,6 +162,7 @@
}
/** List of {@link TaskFragmentAnimationAdapter} to handle animations on all window targets. */
+ @NonNull
private List<TaskFragmentAnimationAdapter> createAnimationAdapters(
@WindowManager.TransitionOldType int transit,
@NonNull RemoteAnimationTarget[] targets) {
@@ -180,12 +182,14 @@
}
}
+ @NonNull
private List<TaskFragmentAnimationAdapter> createOpenAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
return createOpenCloseAnimationAdapters(targets, true /* isOpening */,
mAnimationSpec::loadOpenAnimation);
}
+ @NonNull
private List<TaskFragmentAnimationAdapter> createCloseAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
return createOpenCloseAnimationAdapters(targets, false /* isOpening */,
@@ -196,6 +200,7 @@
* Creates {@link TaskFragmentAnimationAdapter} for OPEN and CLOSE types of transition.
* @param isOpening {@code true} for OPEN type, {@code false} for CLOSE type.
*/
+ @NonNull
private List<TaskFragmentAnimationAdapter> createOpenCloseAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets, boolean isOpening,
@NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider) {
@@ -238,6 +243,7 @@
return adapters;
}
+ @NonNull
private TaskFragmentAnimationAdapter createOpenCloseAnimationAdapter(
@NonNull RemoteAnimationTarget target,
@NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider,
@@ -259,6 +265,7 @@
return new TaskFragmentAnimationAdapter(animation, target);
}
+ @NonNull
private List<TaskFragmentAnimationAdapter> createChangeAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
index 5cc496a..97d42391b 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
@@ -26,6 +26,7 @@
import android.os.Handler;
import android.provider.Settings;
import android.view.RemoteAnimationTarget;
+import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
@@ -68,16 +69,14 @@
// The transition animation should be adjusted based on the developer option.
final ContentResolver resolver = mContext.getContentResolver();
- mTransitionAnimationScaleSetting = Settings.Global.getFloat(resolver,
- Settings.Global.TRANSITION_ANIMATION_SCALE,
- mContext.getResources().getFloat(
- R.dimen.config_appTransitionAnimationDurationScaleDefault));
+ mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting();
resolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE), false,
new SettingsObserver(handler));
}
/** For target that doesn't need to be animated. */
+ @NonNull
static Animation createNoopAnimation(@NonNull RemoteAnimationTarget target) {
// Noop but just keep the target showing/hiding.
final float alpha = target.mode == MODE_CLOSING ? 0f : 1f;
@@ -85,6 +84,7 @@
}
/** Animation for target that is opening in a change transition. */
+ @NonNull
Animation createChangeBoundsOpenAnimation(@NonNull RemoteAnimationTarget target) {
final Rect bounds = target.localBounds;
// The target will be animated in from left or right depends on its position.
@@ -101,6 +101,7 @@
}
/** Animation for target that is closing in a change transition. */
+ @NonNull
Animation createChangeBoundsCloseAnimation(@NonNull RemoteAnimationTarget target) {
final Rect bounds = target.localBounds;
// The target will be animated out to left or right depends on its position.
@@ -121,6 +122,7 @@
* @return the return array always has two elements. The first one is for the start leash, and
* the second one is for the end leash.
*/
+ @NonNull
Animation[] createChangeBoundsChangeAnimations(@NonNull RemoteAnimationTarget target) {
// Both start bounds and end bounds are in screen coordinates. We will post translate
// to the local coordinates in TaskFragmentAnimationAdapter#onAnimationUpdate
@@ -177,6 +179,7 @@
return new Animation[]{startSet, endSet};
}
+ @NonNull
Animation loadOpenAnimation(@NonNull RemoteAnimationTarget target,
@NonNull Rect wholeAnimationBounds) {
final boolean isEnter = target.mode != MODE_CLOSING;
@@ -198,6 +201,7 @@
return animation;
}
+ @NonNull
Animation loadCloseAnimation(@NonNull RemoteAnimationTarget target,
@NonNull Rect wholeAnimationBounds) {
final boolean isEnter = target.mode != MODE_CLOSING;
@@ -217,6 +221,12 @@
return animation;
}
+ private float getTransitionAnimationScaleSetting() {
+ return WindowManager.fixScale(Settings.Global.getFloat(mContext.getContentResolver(),
+ Settings.Global.TRANSITION_ANIMATION_SCALE, mContext.getResources().getFloat(
+ R.dimen.config_appTransitionAnimationDurationScaleDefault)));
+ }
+
private class SettingsObserver extends ContentObserver {
SettingsObserver(@NonNull Handler handler) {
super(handler);
@@ -224,9 +234,7 @@
@Override
public void onChange(boolean selfChange) {
- mTransitionAnimationScaleSetting = Settings.Global.getFloat(
- mContext.getContentResolver(), Settings.Global.TRANSITION_ANIMATION_SCALE,
- mTransitionAnimationScaleSetting);
+ mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting();
}
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 37f5b6d..11c0db3 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -18,8 +18,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.Activity;
import android.app.WindowConfiguration.WindowingMode;
import android.content.Intent;
@@ -30,6 +28,9 @@
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
@@ -175,6 +176,7 @@
&& mInfo.getActivities().size() == collectNonFinishingActivities().size();
}
+ @NonNull
ActivityStack toActivityStack() {
return new ActivityStack(collectNonFinishingActivities(), isEmpty());
}
@@ -249,19 +251,22 @@
return mInfo;
}
- void setInfo(@NonNull TaskFragmentInfo info) {
+ void setInfo(@NonNull WindowContainerTransaction wct, @NonNull TaskFragmentInfo info) {
if (!mIsFinished && mInfo == null && info.isEmpty()) {
// onTaskFragmentAppeared with empty info. We will remove the TaskFragment if no
// pending appeared intent/activities. Otherwise, wait and removing the TaskFragment if
// it is still empty after timeout.
- mAppearEmptyTimeout = () -> {
- mAppearEmptyTimeout = null;
- mController.onTaskFragmentAppearEmptyTimeout(this);
- };
if (mPendingAppearedIntent != null || !mPendingAppearedActivities.isEmpty()) {
+ mAppearEmptyTimeout = () -> {
+ mAppearEmptyTimeout = null;
+ // Call without the pass-in wct when timeout. We need to applyWct directly
+ // in this case.
+ mController.onTaskFragmentAppearEmptyTimeout(this);
+ };
mController.getHandler().postDelayed(mAppearEmptyTimeout, APPEAR_EMPTY_TIMEOUT_MS);
} else {
- mAppearEmptyTimeout.run();
+ mAppearEmptyTimeout = null;
+ mController.onTaskFragmentAppearEmptyTimeout(wct, this);
}
} else if (mAppearEmptyTimeout != null && !info.isEmpty()) {
mController.getHandler().removeCallbacks(mAppearEmptyTimeout);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index 4d25952..21cf7a6 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -56,6 +56,8 @@
* Build/Install/Run:
* atest WMJetpackUnitTests:JetpackTaskFragmentOrganizerTest
*/
+// Suppress GuardedBy warning on unit tests
+@SuppressWarnings("GuardedBy")
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -119,7 +121,7 @@
new Intent(), taskContainer, mSplitController);
final TaskFragmentInfo info = createMockInfo(container);
mOrganizer.mFragmentInfos.put(container.getTaskFragmentToken(), info);
- container.setInfo(info);
+ container.setInfo(mTransaction, info);
mOrganizer.expandTaskFragment(mTransaction, container.getTaskFragmentToken());
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 4bc5033..07758d2 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -89,6 +89,8 @@
* Build/Install/Run:
* atest WMJetpackUnitTests:SplitControllerTest
*/
+// Suppress GuardedBy warning on unit tests
+@SuppressWarnings("GuardedBy")
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -158,14 +160,14 @@
final TaskFragmentInfo info = mock(TaskFragmentInfo.class);
doReturn(new ArrayList<>()).when(info).getActivities();
doReturn(true).when(info).isEmpty();
- tf1.setInfo(info);
+ tf1.setInfo(mTransaction, info);
assertWithMessage("Must return tf because we are waiting for tf1 to become non-empty after"
+ " creation.")
.that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf1);
doReturn(false).when(info).isEmpty();
- tf1.setInfo(info);
+ tf1.setInfo(mTransaction, info);
assertWithMessage("Must return null because tf1 becomes empty.")
.that(mSplitController.getTopActiveContainer(TASK_ID)).isNull();
@@ -177,7 +179,7 @@
doReturn(tf.getTaskFragmentToken()).when(mInfo).getFragmentToken();
// The TaskFragment has been removed in the server, we only need to cleanup the reference.
- mSplitController.onTaskFragmentVanished(mInfo);
+ mSplitController.onTaskFragmentVanished(mTransaction, mInfo);
verify(mSplitPresenter, never()).deleteTaskFragment(any(), any());
verify(mSplitController).removeContainer(tf);
@@ -187,9 +189,10 @@
@Test
public void testOnTaskFragmentAppearEmptyTimeout() {
final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID);
- mSplitController.onTaskFragmentAppearEmptyTimeout(tf);
+ mSplitController.onTaskFragmentAppearEmptyTimeout(mTransaction, tf);
- verify(mSplitPresenter).cleanupContainer(tf, false /* shouldFinishDependent */);
+ verify(mSplitPresenter).cleanupContainer(mTransaction, tf,
+ false /* shouldFinishDependent */);
}
@Test
@@ -229,8 +232,8 @@
spyOn(tf);
doReturn(mActivity).when(tf).getTopNonFinishingActivity();
doReturn(true).when(tf).isEmpty();
- doReturn(true).when(mSplitController).launchPlaceholderIfNecessary(mActivity,
- false /* isOnCreated */);
+ doReturn(true).when(mSplitController).launchPlaceholderIfNecessary(mTransaction,
+ mActivity, false /* isOnCreated */);
doNothing().when(mSplitPresenter).updateSplitContainer(any(), any(), any());
mSplitController.updateContainer(mTransaction, tf);
@@ -250,7 +253,7 @@
mSplitController.updateContainer(mTransaction, tf);
- verify(mSplitController, never()).dismissPlaceholderIfNecessary(any());
+ verify(mSplitController, never()).dismissPlaceholderIfNecessary(any(), any());
// Verify if tf is not in the top splitContainer,
final SplitContainer splitContainer = mock(SplitContainer.class);
@@ -264,7 +267,7 @@
mSplitController.updateContainer(mTransaction, tf);
- verify(mSplitController, never()).dismissPlaceholderIfNecessary(any());
+ verify(mSplitController, never()).dismissPlaceholderIfNecessary(any(), any());
// Verify if one or both containers in the top SplitContainer are finished,
// dismissPlaceholder() won't be called.
@@ -273,12 +276,12 @@
mSplitController.updateContainer(mTransaction, tf);
- verify(mSplitController, never()).dismissPlaceholderIfNecessary(any());
+ verify(mSplitController, never()).dismissPlaceholderIfNecessary(any(), any());
// Verify if placeholder should be dismissed, updateSplitContainer() won't be called.
doReturn(false).when(tf).isFinished();
doReturn(true).when(mSplitController)
- .dismissPlaceholderIfNecessary(splitContainer);
+ .dismissPlaceholderIfNecessary(mTransaction, splitContainer);
mSplitController.updateContainer(mTransaction, tf);
@@ -286,7 +289,7 @@
// Verify if the top active split is updated if both of its containers are not finished.
doReturn(false).when(mSplitController)
- .dismissPlaceholderIfNecessary(splitContainer);
+ .dismissPlaceholderIfNecessary(mTransaction, splitContainer);
mSplitController.updateContainer(mTransaction, tf);
@@ -315,34 +318,36 @@
@Test
public void testOnActivityCreated() {
- mSplitController.onActivityCreated(mActivity);
+ mSplitController.onActivityCreated(mTransaction, mActivity);
// Disallow to split as primary because we want the new launch to be always on top.
- verify(mSplitController).resolveActivityToContainer(mActivity, false /* isOnReparent */);
+ verify(mSplitController).resolveActivityToContainer(mTransaction, mActivity,
+ false /* isOnReparent */);
}
@Test
- public void testOnActivityReparentToTask_sameProcess() {
- mSplitController.onActivityReparentToTask(TASK_ID, new Intent(),
+ public void testOnActivityReparentedToTask_sameProcess() {
+ mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, new Intent(),
mActivity.getActivityToken());
// Treated as on activity created, but allow to split as primary.
- verify(mSplitController).resolveActivityToContainer(mActivity, true /* isOnReparent */);
+ verify(mSplitController).resolveActivityToContainer(mTransaction,
+ mActivity, true /* isOnReparent */);
// Try to place the activity to the top TaskFragment when there is no matched rule.
- verify(mSplitController).placeActivityInTopContainer(mActivity);
+ verify(mSplitController).placeActivityInTopContainer(mTransaction, mActivity);
}
@Test
- public void testOnActivityReparentToTask_diffProcess() {
+ public void testOnActivityReparentedToTask_diffProcess() {
// Create an empty TaskFragment to initialize for the Task.
mSplitController.newContainer(new Intent(), mActivity, TASK_ID);
final IBinder activityToken = new Binder();
final Intent intent = new Intent();
- mSplitController.onActivityReparentToTask(TASK_ID, intent, activityToken);
+ mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, intent, activityToken);
// Treated as starting new intent
- verify(mSplitController, never()).resolveActivityToContainer(any(), anyBoolean());
+ verify(mSplitController, never()).resolveActivityToContainer(any(), any(), anyBoolean());
verify(mSplitController).resolveStartActivityIntent(any(), eq(TASK_ID), eq(intent),
isNull());
}
@@ -504,26 +509,29 @@
@Test
public void testPlaceActivityInTopContainer() {
- mSplitController.placeActivityInTopContainer(mActivity);
+ mSplitController.placeActivityInTopContainer(mTransaction, mActivity);
- verify(mSplitPresenter, never()).applyTransaction(any());
+ verify(mTransaction, never()).reparentActivityToTaskFragment(any(), any());
- mSplitController.newContainer(new Intent(), mActivity, TASK_ID);
- mSplitController.placeActivityInTopContainer(mActivity);
+ // Place in the top container if there is no other rule matched.
+ final TaskFragmentContainer topContainer = mSplitController
+ .newContainer(new Intent(), mActivity, TASK_ID);
+ mSplitController.placeActivityInTopContainer(mTransaction, mActivity);
- verify(mSplitPresenter).applyTransaction(any());
+ verify(mTransaction).reparentActivityToTaskFragment(topContainer.getTaskFragmentToken(),
+ mActivity.getActivityToken());
// Not reparent if activity is in a TaskFragment.
- clearInvocations(mSplitPresenter);
+ clearInvocations(mTransaction);
mSplitController.newContainer(mActivity, TASK_ID);
- mSplitController.placeActivityInTopContainer(mActivity);
+ mSplitController.placeActivityInTopContainer(mTransaction, mActivity);
- verify(mSplitPresenter, never()).applyTransaction(any());
+ verify(mTransaction, never()).reparentActivityToTaskFragment(any(), any());
}
@Test
public void testResolveActivityToContainer_noRuleMatched() {
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertFalse(result);
@@ -535,7 +543,7 @@
setupExpandRule(mActivity);
// When the activity is not in any TaskFragment, create a new expanded TaskFragment for it.
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
final TaskFragmentContainer container = mSplitController.getContainerWithActivity(
mActivity);
@@ -543,7 +551,8 @@
assertTrue(result);
assertNotNull(container);
verify(mSplitController).newContainer(mActivity, TASK_ID);
- verify(mSplitPresenter).expandActivity(container.getTaskFragmentToken(), mActivity);
+ verify(mSplitPresenter).expandActivity(mTransaction, container.getTaskFragmentToken(),
+ mActivity);
}
@Test
@@ -552,11 +561,11 @@
// When the activity is not in any TaskFragment, create a new expanded TaskFragment for it.
final TaskFragmentContainer container = mSplitController.newContainer(mActivity, TASK_ID);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertTrue(result);
- verify(mSplitPresenter).expandTaskFragment(container.getTaskFragmentToken());
+ verify(mSplitPresenter).expandTaskFragment(mTransaction, container.getTaskFragmentToken());
}
@Test
@@ -566,14 +575,15 @@
// When the activity is not in any TaskFragment, create a new expanded TaskFragment for it.
final Activity activity = createMockActivity();
addSplitTaskFragments(activity, mActivity);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
final TaskFragmentContainer container = mSplitController.getContainerWithActivity(
mActivity);
assertTrue(result);
assertNotNull(container);
- verify(mSplitPresenter).expandActivity(container.getTaskFragmentToken(), mActivity);
+ verify(mSplitPresenter).expandActivity(mTransaction, container.getTaskFragmentToken(),
+ mActivity);
}
@Test
@@ -583,11 +593,11 @@
(SplitPlaceholderRule) mSplitController.getSplitRules().get(0);
// Launch placeholder if the activity is not in any TaskFragment.
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertTrue(result);
- verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT,
+ verify(mSplitPresenter).startActivityToSide(mTransaction, mActivity, PLACEHOLDER_INTENT,
mSplitController.getPlaceholderOptions(mActivity, true /* isOnCreated */),
placeholderRule, true /* isPlaceholder */);
}
@@ -600,11 +610,11 @@
final Activity activity = createMockActivity();
mSplitController.newContainer(mActivity, TASK_ID);
mSplitController.newContainer(activity, TASK_ID);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertFalse(result);
- verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(),
+ verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), any(),
anyBoolean());
}
@@ -616,11 +626,11 @@
// Launch placeholder if the activity is in the topmost expanded TaskFragment.
mSplitController.newContainer(mActivity, TASK_ID);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertTrue(result);
- verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT,
+ verify(mSplitPresenter).startActivityToSide(mTransaction, mActivity, PLACEHOLDER_INTENT,
mSplitController.getPlaceholderOptions(mActivity, true /* isOnCreated */),
placeholderRule, true /* isPlaceholder */);
}
@@ -632,11 +642,11 @@
// Don't launch placeholder if the activity is in primary split.
final Activity secondaryActivity = createMockActivity();
addSplitTaskFragments(mActivity, secondaryActivity);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertFalse(result);
- verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(),
+ verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), any(),
anyBoolean());
}
@@ -649,11 +659,11 @@
// Launch placeholder if the activity is in secondary split.
final Activity primaryActivity = createMockActivity();
addSplitTaskFragments(primaryActivity, mActivity);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertTrue(result);
- verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT,
+ verify(mSplitPresenter).startActivityToSide(mTransaction, mActivity, PLACEHOLDER_INTENT,
mSplitController.getPlaceholderOptions(mActivity, true /* isOnCreated */),
placeholderRule, true /* isPlaceholder */);
}
@@ -676,7 +686,7 @@
secondaryContainer,
splitRule);
clearInvocations(mSplitController);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertTrue(result);
@@ -705,7 +715,7 @@
final Activity launchedActivity = createMockActivity();
primaryContainer.addPendingAppearedActivity(launchedActivity);
- assertFalse(mSplitController.resolveActivityToContainer(launchedActivity,
+ assertFalse(mSplitController.resolveActivityToContainer(mTransaction, launchedActivity,
false /* isOnReparent */));
}
@@ -717,7 +727,7 @@
// Activity is already in secondary split, no need to create new split.
addSplitTaskFragments(primaryActivity, mActivity);
clearInvocations(mSplitController);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertTrue(result);
@@ -735,7 +745,7 @@
addSplitTaskFragments(primaryActivity, secondaryActivity);
mSplitController.getContainerWithActivity(secondaryActivity)
.addPendingAppearedActivity(mActivity);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertFalse(result);
@@ -760,7 +770,7 @@
mActivity,
secondaryContainer,
placeholderRule);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertTrue(result);
@@ -774,7 +784,7 @@
final TaskFragmentContainer container = mSplitController.newContainer(activityBelow,
TASK_ID);
container.addPendingAppearedActivity(mActivity);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertTrue(result);
@@ -790,14 +800,15 @@
final TaskFragmentContainer container = mSplitController.newContainer(activityBelow,
TASK_ID);
container.addPendingAppearedActivity(mActivity);
- boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertFalse(result);
assertEquals(container, mSplitController.getContainerWithActivity(mActivity));
// Allow to split as primary.
- result = mSplitController.resolveActivityToContainer(mActivity, true /* isOnReparent */);
+ result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
+ true /* isOnReparent */);
assertTrue(result);
assertSplitPair(mActivity, activityBelow);
@@ -815,7 +826,7 @@
final TaskFragmentContainer secondaryContainer = mSplitController.getContainerWithActivity(
activityBelow);
secondaryContainer.addPendingAppearedActivity(mActivity);
- final boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
final TaskFragmentContainer container = mSplitController.getContainerWithActivity(
mActivity);
@@ -836,14 +847,15 @@
final TaskFragmentContainer primaryContainer = mSplitController.getContainerWithActivity(
primaryActivity);
primaryContainer.addPendingAppearedActivity(mActivity);
- boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertFalse(result);
assertEquals(primaryContainer, mSplitController.getContainerWithActivity(mActivity));
- result = mSplitController.resolveActivityToContainer(mActivity, true /* isOnReparent */);
+ result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
+ true /* isOnReparent */);
assertTrue(result);
assertSplitPair(mActivity, primaryActivity);
@@ -861,7 +873,7 @@
container.addPendingAppearedActivity(mActivity);
// Allow to split as primary.
- boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
true /* isOnReparent */);
assertTrue(result);
@@ -879,15 +891,13 @@
TASK_ID);
container.addPendingAppearedActivity(mActivity);
- boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertTrue(result);
assertSplitPair(activityBelow, mActivity, true /* matchParentBounds */);
}
- // Suppress GuardedBy warning on unit tests
- @SuppressWarnings("GuardedBy")
@Test
public void testResolveActivityToContainer_minDimensions_shouldExpandSplitContainer() {
final Activity primaryActivity = createMockActivity();
@@ -899,14 +909,14 @@
doReturn(secondaryActivity).when(mSplitController).findActivityBelow(eq(mActivity));
clearInvocations(mSplitPresenter);
- boolean result = mSplitController.resolveActivityToContainer(mActivity,
+ boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
assertTrue(result);
assertSplitPair(primaryActivity, mActivity, true /* matchParentBounds */);
assertEquals(mSplitController.getContainerWithActivity(secondaryActivity),
mSplitController.getContainerWithActivity(mActivity));
- verify(mSplitPresenter, never()).createNewSplitContainer(any(), any(), any());
+ verify(mSplitPresenter, never()).createNewSplitContainer(any(), any(), any(), any());
}
@Test
@@ -914,7 +924,7 @@
doReturn(new Binder()).when(mSplitController).getInitialTaskFragmentToken(mActivity);
// No need to handle when the new launched activity is in an unknown TaskFragment.
- assertTrue(mSplitController.resolveActivityToContainer(mActivity,
+ assertTrue(mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */));
}
@@ -993,7 +1003,7 @@
private void setupTaskFragmentInfo(@NonNull TaskFragmentContainer container,
@NonNull Activity activity) {
final TaskFragmentInfo info = createMockTaskFragmentInfo(container, activity);
- container.setInfo(info);
+ container.setInfo(mTransaction, info);
mSplitPresenter.mFragmentInfos.put(container.getTaskFragmentToken(), info);
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
index d7931966..3fdf8e5 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
@@ -78,6 +78,8 @@
* Build/Install/Run:
* atest WMJetpackUnitTests:SplitPresenterTest
*/
+// Suppress GuardedBy warning on unit tests
+@SuppressWarnings("GuardedBy")
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -226,8 +228,9 @@
mTransaction, splitContainer, mActivity, secondaryActivity,
null /* secondaryIntent */));
- primaryTf.setInfo(createMockTaskFragmentInfo(primaryTf, mActivity));
- secondaryTf.setInfo(createMockTaskFragmentInfo(secondaryTf, secondaryActivity));
+ primaryTf.setInfo(mTransaction, createMockTaskFragmentInfo(primaryTf, mActivity));
+ secondaryTf.setInfo(mTransaction,
+ createMockTaskFragmentInfo(secondaryTf, secondaryActivity));
assertEquals(RESULT_EXPANDED, mPresenter.expandSplitContainerIfNeeded(mTransaction,
splitContainer, mActivity, secondaryActivity, null /* secondaryIntent */));
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index 44c7e6c..6cbecff 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -19,6 +19,8 @@
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.junit.Assert.assertEquals;
@@ -36,7 +38,6 @@
import android.app.Activity;
import android.content.Intent;
import android.os.Binder;
-import android.os.Handler;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.window.TaskFragmentInfo;
@@ -62,25 +63,27 @@
* Build/Install/Run:
* atest WMJetpackUnitTests:TaskFragmentContainerTest
*/
+// Suppress GuardedBy warning on unit tests
+@SuppressWarnings("GuardedBy")
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TaskFragmentContainerTest {
@Mock
private SplitPresenter mPresenter;
- @Mock
private SplitController mController;
@Mock
private TaskFragmentInfo mInfo;
@Mock
- private Handler mHandler;
+ private WindowContainerTransaction mTransaction;
private Activity mActivity;
private Intent mIntent;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- doReturn(mHandler).when(mController).getHandler();
+ mController = new SplitController();
+ spyOn(mController);
mActivity = createMockActivity();
mIntent = new Intent();
}
@@ -123,7 +126,7 @@
// Remove all references after the container has appeared in server.
doReturn(new ArrayList<>()).when(mInfo).getActivities();
- container.setInfo(mInfo);
+ container.setInfo(mTransaction, mInfo);
container.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
verify(mActivity, never()).finish();
@@ -137,7 +140,7 @@
final TaskFragmentContainer container0 = new TaskFragmentContainer(mActivity,
null /* pendingAppearedIntent */, taskContainer, mController);
final TaskFragmentInfo info = createMockTaskFragmentInfo(container0, mActivity);
- container0.setInfo(info);
+ container0.setInfo(mTransaction, info);
// Request to reparent the activity to a new TaskFragment.
final TaskFragmentContainer container1 = new TaskFragmentContainer(mActivity,
null /* pendingAppearedIntent */, taskContainer, mController);
@@ -163,7 +166,7 @@
final TaskFragmentInfo info0 = createMockTaskFragmentInfo(pendingActivityContainer,
mActivity);
- pendingActivityContainer.setInfo(info0);
+ pendingActivityContainer.setInfo(mTransaction, info0);
assertTrue(pendingActivityContainer.mPendingAppearedActivities.isEmpty());
@@ -175,7 +178,7 @@
final TaskFragmentInfo info1 = createMockTaskFragmentInfo(pendingIntentContainer,
mActivity);
- pendingIntentContainer.setInfo(info1);
+ pendingIntentContainer.setInfo(mTransaction, info1);
assertNull(pendingIntentContainer.getPendingAppearedIntent());
}
@@ -191,18 +194,19 @@
final TaskFragmentInfo info = mock(TaskFragmentInfo.class);
doReturn(new ArrayList<>()).when(info).getActivities();
doReturn(true).when(info).isEmpty();
- container.setInfo(info);
+ container.setInfo(mTransaction, info);
assertTrue(container.isWaitingActivityAppear());
doReturn(false).when(info).isEmpty();
- container.setInfo(info);
+ container.setInfo(mTransaction, info);
assertFalse(container.isWaitingActivityAppear());
}
@Test
public void testAppearEmptyTimeout() {
+ doNothing().when(mController).onTaskFragmentAppearEmptyTimeout(any(), any());
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
mIntent, taskContainer, mController);
@@ -213,20 +217,20 @@
final TaskFragmentInfo info = mock(TaskFragmentInfo.class);
container.mInfo = null;
doReturn(true).when(info).isEmpty();
- container.setInfo(info);
+ container.setInfo(mTransaction, info);
assertNotNull(container.mAppearEmptyTimeout);
// Not set if it is not appeared empty.
doReturn(new ArrayList<>()).when(info).getActivities();
doReturn(false).when(info).isEmpty();
- container.setInfo(info);
+ container.setInfo(mTransaction, info);
assertNull(container.mAppearEmptyTimeout);
// Remove timeout after the container becomes non-empty.
doReturn(false).when(info).isEmpty();
- container.setInfo(info);
+ container.setInfo(mTransaction, info);
assertNull(container.mAppearEmptyTimeout);
@@ -234,7 +238,7 @@
container.mInfo = null;
container.setPendingAppearedIntent(mIntent);
doReturn(true).when(info).isEmpty();
- container.setInfo(info);
+ container.setInfo(mTransaction, info);
container.mAppearEmptyTimeout.run();
assertNull(container.mAppearEmptyTimeout);
@@ -260,7 +264,7 @@
final List<IBinder> runningActivities = Lists.newArrayList(activity0.getActivityToken(),
activity1.getActivityToken());
doReturn(runningActivities).when(mInfo).getActivities();
- container.setInfo(mInfo);
+ container.setInfo(mTransaction, mInfo);
activities = container.collectNonFinishingActivities();
assertEquals(3, activities.size());
@@ -295,7 +299,7 @@
final Activity activity = createMockActivity();
final List<IBinder> runningActivities = Lists.newArrayList(activity.getActivityToken());
doReturn(runningActivities).when(mInfo).getActivities();
- container.setInfo(mInfo);
+ container.setInfo(mTransaction, mInfo);
assertEquals(activity, container.getBottomMostActivity());
}
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index 918e514..e9a1721 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
index 764e650..b085b73 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
@@ -16,14 +16,20 @@
package com.android.wm.shell;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
+
+import android.app.WindowConfiguration;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.window.DisplayAreaAppearedInfo;
import android.window.DisplayAreaInfo;
import android.window.DisplayAreaOrganizer;
+import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
+import com.android.internal.protolog.common.ProtoLog;
+
import java.io.PrintWriter;
import java.util.List;
import java.util.concurrent.Executor;
@@ -102,10 +108,44 @@
mDisplayAreasInfo.put(displayId, displayAreaInfo);
}
+ /**
+ * Create a {@link WindowContainerTransaction} to update display windowing mode.
+ *
+ * @param displayId display id to update windowing mode for
+ * @param windowingMode target {@link WindowConfiguration.WindowingMode}
+ * @return {@link WindowContainerTransaction} with pending operation to set windowing mode
+ */
+ public WindowContainerTransaction prepareWindowingModeChange(int displayId,
+ @WindowConfiguration.WindowingMode int windowingMode) {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ DisplayAreaInfo displayAreaInfo = mDisplayAreasInfo.get(displayId);
+ if (displayAreaInfo == null) {
+ ProtoLog.e(WM_SHELL_DESKTOP_MODE,
+ "unable to update windowing mode for display %d display not found", displayId);
+ return wct;
+ }
+
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE,
+ "setWindowingMode: displayId=%d current wmMode=%d new wmMode=%d", displayId,
+ displayAreaInfo.configuration.windowConfiguration.getWindowingMode(),
+ windowingMode);
+
+ wct.setWindowingMode(displayAreaInfo.token, windowingMode);
+ return wct;
+ }
+
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
final String childPrefix = innerPrefix + " ";
pw.println(prefix + this);
+
+ for (int i = 0; i < mDisplayAreasInfo.size(); i++) {
+ int displayId = mDisplayAreasInfo.keyAt(i);
+ DisplayAreaInfo displayAreaInfo = mDisplayAreasInfo.get(displayId);
+ int windowingMode =
+ displayAreaInfo.configuration.windowConfiguration.getWindowingMode();
+ pw.println(innerPrefix + "# displayId=" + displayId + " wmMode=" + windowingMode);
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 6ae0f9b..d5d4935 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -22,6 +22,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -46,6 +47,7 @@
import android.window.StartingWindowRemovalInfo;
import android.window.TaskAppearedInfo;
import android.window.TaskOrganizer;
+import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -690,6 +692,49 @@
taskListener.reparentChildSurfaceToTask(taskId, sc, t);
}
+ /**
+ * Create a {@link WindowContainerTransaction} to clear task bounds.
+ *
+ * @param displayId display id for tasks that will have bounds cleared
+ * @return {@link WindowContainerTransaction} with pending operations to clear bounds
+ */
+ public WindowContainerTransaction prepareClearBoundsForTasks(int displayId) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearBoundsForTasks: displayId=%d", displayId);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ for (int i = 0; i < mTasks.size(); i++) {
+ RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo();
+ if (taskInfo.displayId == displayId) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "clearing bounds for token=%s taskInfo=%s",
+ taskInfo.token, taskInfo);
+ wct.setBounds(taskInfo.token, null);
+ }
+ }
+ return wct;
+ }
+
+ /**
+ * Create a {@link WindowContainerTransaction} to clear task level freeform setting.
+ *
+ * @param displayId display id for tasks that will have windowing mode reset to {@link
+ * WindowConfiguration#WINDOWING_MODE_UNDEFINED}
+ * @return {@link WindowContainerTransaction} with pending operations to clear windowing mode
+ */
+ public WindowContainerTransaction prepareClearFreeformForTasks(int displayId) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearFreeformForTasks: displayId=%d", displayId);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ for (int i = 0; i < mTasks.size(); i++) {
+ RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo();
+ if (taskInfo.displayId == displayId
+ && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE,
+ "clearing windowing mode for token=%s taskInfo=%s", taskInfo.token,
+ taskInfo);
+ wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
+ }
+ }
+ return wct;
+ }
+
private void logSizeCompatRestartButtonEventReported(@NonNull TaskAppearedInfo info,
int event) {
ActivityInfo topActivityInfo = info.getTaskInfo().topActivityInfo;
@@ -816,7 +861,14 @@
final int key = mTasks.keyAt(i);
final TaskAppearedInfo info = mTasks.valueAt(i);
final TaskListener listener = getTaskListener(info.getTaskInfo());
- pw.println(innerPrefix + "#" + i + " task=" + key + " listener=" + listener);
+ final int windowingMode = info.getTaskInfo().getWindowingMode();
+ String pkg = "";
+ if (info.getTaskInfo().baseActivity != null) {
+ pkg = info.getTaskInfo().baseActivity.getPackageName();
+ }
+ Rect bounds = info.getTaskInfo().getConfiguration().windowConfiguration.getBounds();
+ pw.println(innerPrefix + "#" + i + " task=" + key + " listener=" + listener
+ + " wmMode=" + windowingMode + " pkg=" + pkg + " bounds=" + bounds);
}
pw.println();
@@ -826,6 +878,7 @@
final TaskListener listener = mLaunchCookieToListener.valueAt(i);
pw.println(innerPrefix + "#" + i + " cookie=" + key + " listener=" + listener);
}
+
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index d28a68a..a8764e0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -54,7 +54,10 @@
/** Callback for listening task state. */
public interface Listener {
- /** Called when the container is ready for launching activities. */
+ /**
+ * Only called once when the surface has been created & the container is ready for
+ * launching activities.
+ */
default void onInitialized() {}
/** Called when the container can no longer launch activities. */
@@ -80,12 +83,13 @@
private final SyncTransactionQueue mSyncQueue;
private final TaskViewTransitions mTaskViewTransitions;
- private ActivityManager.RunningTaskInfo mTaskInfo;
+ protected ActivityManager.RunningTaskInfo mTaskInfo;
private WindowContainerToken mTaskToken;
private SurfaceControl mTaskLeash;
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
private boolean mSurfaceCreated;
private boolean mIsInitialized;
+ private boolean mNotifiedForInitialized;
private Listener mListener;
private Executor mListenerExecutor;
private Region mObscuredTouchRegion;
@@ -110,6 +114,13 @@
mGuard.open("release");
}
+ /**
+ * @return {@code True} when the TaskView's surface has been created, {@code False} otherwise.
+ */
+ public boolean isInitialized() {
+ return mIsInitialized;
+ }
+
/** Until all users are converted, we may have mixed-use (eg. Car). */
private boolean isUsingShellTransitions() {
return mTaskViewTransitions != null && Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -269,11 +280,17 @@
resetTaskInfo();
});
mGuard.close();
- if (mListener != null && mIsInitialized) {
+ mIsInitialized = false;
+ notifyReleased();
+ }
+
+ /** Called when the {@link TaskView} has been released. */
+ protected void notifyReleased() {
+ if (mListener != null && mNotifiedForInitialized) {
mListenerExecutor.execute(() -> {
mListener.onReleased();
});
- mIsInitialized = false;
+ mNotifiedForInitialized = false;
}
}
@@ -407,12 +424,8 @@
@Override
public void surfaceCreated(SurfaceHolder holder) {
mSurfaceCreated = true;
- if (mListener != null && !mIsInitialized) {
- mIsInitialized = true;
- mListenerExecutor.execute(() -> {
- mListener.onInitialized();
- });
- }
+ mIsInitialized = true;
+ notifyInitialized();
mShellExecutor.execute(() -> {
if (mTaskToken == null) {
// Nothing to update, task is not yet available
@@ -430,6 +443,16 @@
});
}
+ /** Called when the {@link TaskView} is initialized. */
+ protected void notifyInitialized() {
+ if (mListener != null && !mNotifiedForInitialized) {
+ mNotifiedForInitialized = true;
+ mListenerExecutor.execute(() -> {
+ mListener.onInitialized();
+ });
+ }
+ }
+
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mTaskToken == null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index d5875c0..e270edb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -221,8 +221,7 @@
}
final Display display = mDisplayController.getDisplay(mDisplayId);
SurfaceControlViewHost viewRoot =
- new SurfaceControlViewHost(
- view.getContext(), display, wwm, true /* useSfChoreographer */);
+ new SurfaceControlViewHost(view.getContext(), display, wwm);
attrs.flags |= FLAG_HARDWARE_ACCELERATED;
viewRoot.setView(view, attrs);
mViewRoots.put(view, viewRoot);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 85c8ebf..83ba909 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -80,7 +80,10 @@
public static final int PARALLAX_DISMISSING = 1;
public static final int PARALLAX_ALIGN_CENTER = 2;
- private static final int FLING_ANIMATION_DURATION = 250;
+ private static final int FLING_RESIZE_DURATION = 250;
+ private static final int FLING_SWITCH_DURATION = 350;
+ private static final int FLING_ENTER_DURATION = 350;
+ private static final int FLING_EXIT_DURATION = 350;
private final int mDividerWindowWidth;
private final int mDividerInsets;
@@ -93,6 +96,9 @@
private final Rect mBounds1 = new Rect();
// Bounds2 final position should be always at bottom or right
private final Rect mBounds2 = new Rect();
+ // The temp bounds outside of display bounds for side stage when split screen inactive to avoid
+ // flicker next time active split screen.
+ private final Rect mInvisibleBounds = new Rect();
private final Rect mWinBounds1 = new Rect();
private final Rect mWinBounds2 = new Rect();
private final SplitLayoutHandler mSplitLayoutHandler;
@@ -141,6 +147,10 @@
resetDividerPosition();
mDimNonImeSide = resources.getBoolean(R.bool.config_dimNonImeAttachedSide);
+
+ mInvisibleBounds.set(mRootBounds);
+ mInvisibleBounds.offset(isLandscape() ? mRootBounds.right : 0,
+ isLandscape() ? 0 : mRootBounds.bottom);
}
private int getDividerInsets(Resources resources, Display display) {
@@ -239,6 +249,12 @@
rect.offset(-mRootBounds.left, -mRootBounds.top);
}
+ /** Gets bounds size equal to root bounds but outside of screen, used for position side stage
+ * when split inactive to avoid flicker when next time active. */
+ public void getInvisibleBounds(Rect rect) {
+ rect.set(mInvisibleBounds);
+ }
+
/** Returns leash of the current divider bar. */
@Nullable
public SurfaceControl getDividerLeash() {
@@ -284,6 +300,10 @@
mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
initDividerPosition(mTempRect);
+ mInvisibleBounds.set(mRootBounds);
+ mInvisibleBounds.offset(isLandscape() ? mRootBounds.right : 0,
+ isLandscape() ? 0 : mRootBounds.bottom);
+
return true;
}
@@ -405,6 +425,13 @@
mFreezeDividerWindow = freezeDividerWindow;
}
+ /** Update current layout as divider put on start or end position. */
+ public void setDividerAtBorder(boolean start) {
+ final int pos = start ? mDividerSnapAlgorithm.getDismissStartTarget().position
+ : mDividerSnapAlgorithm.getDismissEndTarget().position;
+ setDividePosition(pos, false /* applyLayoutChange */);
+ }
+
/**
* Updates bounds with the passing position. Usually used to update recording bounds while
* performing animation or dragging divider bar to resize the splits.
@@ -449,17 +476,17 @@
public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) {
switch (snapTarget.flag) {
case FLAG_DISMISS_START:
- flingDividePosition(currentPosition, snapTarget.position,
+ flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
() -> mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */,
EXIT_REASON_DRAG_DIVIDER));
break;
case FLAG_DISMISS_END:
- flingDividePosition(currentPosition, snapTarget.position,
+ flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
() -> mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */,
EXIT_REASON_DRAG_DIVIDER));
break;
default:
- flingDividePosition(currentPosition, snapTarget.position,
+ flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
() -> setDividePosition(snapTarget.position, true /* applyLayoutChange */));
break;
}
@@ -516,12 +543,20 @@
public void flingDividerToDismiss(boolean toEnd, int reason) {
final int target = toEnd ? mDividerSnapAlgorithm.getDismissEndTarget().position
: mDividerSnapAlgorithm.getDismissStartTarget().position;
- flingDividePosition(getDividePosition(), target,
+ flingDividePosition(getDividePosition(), target, FLING_EXIT_DURATION,
() -> mSplitLayoutHandler.onSnappedToDismiss(toEnd, reason));
}
+ /** Fling divider from current position to center position. */
+ public void flingDividerToCenter() {
+ final int pos = mDividerSnapAlgorithm.getMiddleTarget().position;
+ flingDividePosition(getDividePosition(), pos, FLING_ENTER_DURATION,
+ () -> setDividePosition(pos, true /* applyLayoutChange */));
+ }
+
@VisibleForTesting
- void flingDividePosition(int from, int to, @Nullable Runnable flingFinishedCallback) {
+ void flingDividePosition(int from, int to, int duration,
+ @Nullable Runnable flingFinishedCallback) {
if (from == to) {
// No animation run, still callback to stop resizing.
mSplitLayoutHandler.onLayoutSizeChanged(this);
@@ -531,7 +566,7 @@
}
ValueAnimator animator = ValueAnimator
.ofInt(from, to)
- .setDuration(FLING_ANIMATION_DURATION);
+ .setDuration(duration);
animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
animator.addUpdateListener(
animation -> updateDivideBounds((int) animation.getAnimatedValue()));
@@ -588,7 +623,7 @@
AnimatorSet set = new AnimatorSet();
set.playTogether(animator1, animator2, animator3);
- set.setDuration(FLING_ANIMATION_DURATION);
+ set.setDuration(FLING_SWITCH_DURATION);
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java
index 35a309a..0cc545a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java
@@ -20,7 +20,6 @@
import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
-import android.animation.AnimationHandler;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
@@ -31,11 +30,9 @@
import androidx.annotation.Nullable;
-import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
import com.android.wm.shell.common.annotations.ExternalMainThread;
import com.android.wm.shell.common.annotations.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
@@ -195,30 +192,6 @@
}
/**
- * Provide a Shell main-thread AnimationHandler. The AnimationHandler can be set on
- * {@link android.animation.ValueAnimator}s and will ensure that the animation will run on
- * the Shell main-thread with the SF vsync.
- */
- @WMSingleton
- @Provides
- @ChoreographerSfVsync
- public static AnimationHandler provideShellMainExecutorSfVsyncAnimationHandler(
- @ShellMainThread ShellExecutor mainExecutor) {
- try {
- AnimationHandler handler = new AnimationHandler();
- mainExecutor.executeBlocking(() -> {
- // This is called on the animation thread since it calls
- // Choreographer.getSfInstance() which returns a thread-local Choreographer instance
- // that uses the SF vsync
- handler.setProvider(new SfVsyncFrameCallbackProvider());
- });
- return handler;
- } catch (InterruptedException e) {
- throw new RuntimeException("Failed to initialize SfVsync animation handler in 1s", e);
- }
- }
-
- /**
* Provides a Shell background thread Handler for low priority background tasks.
*/
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 2ca9c3b..2bcc134 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -27,6 +27,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.launcher3.icons.IconProvider;
+import com.android.wm.shell.RootDisplayAreaOrganizer;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewTransitions;
@@ -48,6 +49,8 @@
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.desktopmode.DesktopModeConstants;
+import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.freeform.FreeformTaskListener;
@@ -574,6 +577,27 @@
}
//
+ // Desktop mode (optional feature)
+ //
+
+ @WMSingleton
+ @Provides
+ static Optional<DesktopModeController> provideDesktopModeController(
+ Context context, ShellInit shellInit,
+ ShellTaskOrganizer shellTaskOrganizer,
+ RootDisplayAreaOrganizer rootDisplayAreaOrganizer,
+ @ShellMainThread Handler mainHandler
+ ) {
+ if (DesktopModeConstants.IS_FEATURE_ENABLED) {
+ return Optional.of(new DesktopModeController(context, shellInit, shellTaskOrganizer,
+ rootDisplayAreaOrganizer,
+ mainHandler));
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ //
// Misc
//
@@ -583,7 +607,8 @@
@ShellCreateTriggerOverride
@Provides
static Object provideIndependentShellComponentsToCreate(
- SplitscreenPipMixedHandler splitscreenPipMixedHandler) {
+ SplitscreenPipMixedHandler splitscreenPipMixedHandler,
+ Optional<DesktopModeController> desktopModeController) {
return new Object();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
new file mode 100644
index 0000000..e62a63a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode;
+
+import android.os.SystemProperties;
+
+/**
+ * Constants for desktop mode feature
+ */
+public class DesktopModeConstants {
+
+ /**
+ * Flag to indicate whether desktop mode is available on the device
+ */
+ public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
+ "persist.wm.debug.desktop_mode", false);
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
new file mode 100644
index 0000000..5849e16
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.window.WindowContainerTransaction;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.RootDisplayAreaOrganizer;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.sysui.ShellInit;
+
+/**
+ * Handles windowing changes when desktop mode system setting changes
+ */
+public class DesktopModeController {
+
+ private final Context mContext;
+ private final ShellTaskOrganizer mShellTaskOrganizer;
+ private final RootDisplayAreaOrganizer mRootDisplayAreaOrganizer;
+ private final SettingsObserver mSettingsObserver;
+
+ public DesktopModeController(Context context, ShellInit shellInit,
+ ShellTaskOrganizer shellTaskOrganizer,
+ RootDisplayAreaOrganizer rootDisplayAreaOrganizer,
+ @ShellMainThread Handler mainHandler) {
+ mContext = context;
+ mShellTaskOrganizer = shellTaskOrganizer;
+ mRootDisplayAreaOrganizer = rootDisplayAreaOrganizer;
+ mSettingsObserver = new SettingsObserver(mContext, mainHandler);
+ shellInit.addInitCallback(this::onInit, this);
+ }
+
+ private void onInit() {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopModeController");
+ mSettingsObserver.observe();
+ }
+
+ @VisibleForTesting
+ void updateDesktopModeEnabled(boolean enabled) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "updateDesktopModeState: enabled=%s", enabled);
+
+ int displayId = mContext.getDisplayId();
+
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ // Reset freeform windowing mode that is set per task level (tasks should inherit
+ // container value)
+ wct.merge(mShellTaskOrganizer.prepareClearFreeformForTasks(displayId), true /* transfer */);
+ int targetWindowingMode;
+ if (enabled) {
+ targetWindowingMode = WINDOWING_MODE_FREEFORM;
+ } else {
+ targetWindowingMode = WINDOWING_MODE_FULLSCREEN;
+ // Clear any resized bounds
+ wct.merge(mShellTaskOrganizer.prepareClearBoundsForTasks(displayId),
+ true /* transfer */);
+ }
+ wct.merge(mRootDisplayAreaOrganizer.prepareWindowingModeChange(displayId,
+ targetWindowingMode), true /* transfer */);
+ mRootDisplayAreaOrganizer.applyTransaction(wct);
+ }
+
+ /**
+ * A {@link ContentObserver} for listening to changes to {@link Settings.System#DESKTOP_MODE}
+ */
+ private final class SettingsObserver extends ContentObserver {
+
+ private final Uri mDesktopModeSetting = Settings.System.getUriFor(
+ Settings.System.DESKTOP_MODE);
+
+ private final Context mContext;
+
+ SettingsObserver(Context context, Handler handler) {
+ super(handler);
+ mContext = context;
+ }
+
+ public void observe() {
+ // TODO(b/242867463): listen for setting change for all users
+ mContext.getContentResolver().registerContentObserver(mDesktopModeSetting,
+ false /* notifyForDescendants */, this /* observer */, UserHandle.USER_CURRENT);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, @Nullable Uri uri) {
+ if (mDesktopModeSetting.equals(uri)) {
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Received update for desktop mode setting");
+ desktopModeSettingChanged();
+ }
+ }
+
+ private void desktopModeSettingChanged() {
+ boolean enabled = isDesktopModeEnabled();
+ updateDesktopModeEnabled(enabled);
+ }
+
+ private boolean isDesktopModeEnabled() {
+ try {
+ int result = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
+ ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result);
+ return result != 0;
+ } catch (Settings.SettingNotFoundException e) {
+ ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
+ return false;
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 4942987..281ea53 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -31,8 +31,6 @@
import android.util.Size;
import android.view.MotionEvent;
import android.view.SurfaceControl;
-import android.view.SyncRtSurfaceTransactionApplier;
-import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowManagerGlobal;
import com.android.internal.protolog.common.ProtoLog;
@@ -42,6 +40,7 @@
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipMediaController.ActionListener;
import com.android.wm.shell.pip.PipMenuController;
+import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -115,6 +114,10 @@
private final ShellExecutor mMainExecutor;
private final Handler mMainHandler;
+ private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
+ mSurfaceControlTransactionFactory;
+ private final float[] mTmpTransform = new float[9];
+
private final ArrayList<Listener> mListeners = new ArrayList<>();
private final SystemWindows mSystemWindows;
private final Optional<SplitScreenController> mSplitScreenController;
@@ -124,7 +127,6 @@
private RemoteAction mCloseAction;
private List<RemoteAction> mMediaActions;
- private SyncRtSurfaceTransactionApplier mApplier;
private int mMenuState;
private PipMenuView mPipMenuView;
@@ -150,6 +152,9 @@
mMainHandler = mainHandler;
mSplitScreenController = splitScreenOptional;
mPipUiEventLogger = pipUiEventLogger;
+
+ mSurfaceControlTransactionFactory =
+ new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
}
public boolean isMenuVisible() {
@@ -194,7 +199,6 @@
return;
}
- mApplier = null;
mSystemWindows.removeView(mPipMenuView);
mPipMenuView = null;
}
@@ -289,7 +293,7 @@
willResizeMenu, withDelay, showResizeHandle, Debug.getCallers(5, " "));
}
- if (!maybeCreateSyncApplier()) {
+ if (!checkPipMenuState()) {
return;
}
@@ -312,7 +316,7 @@
return;
}
- if (!maybeCreateSyncApplier()) {
+ if (!checkPipMenuState()) {
return;
}
@@ -328,18 +332,15 @@
mTmpSourceRectF.set(mTmpSourceBounds);
mTmpDestinationRectF.set(destinationBounds);
mMoveTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
- SurfaceControl surfaceControl = getSurfaceControl();
- SurfaceParams params = new SurfaceParams.Builder(surfaceControl)
- .withMatrix(mMoveTransform)
- .build();
+ final SurfaceControl surfaceControl = getSurfaceControl();
+ final SurfaceControl.Transaction menuTx =
+ mSurfaceControlTransactionFactory.getTransaction();
+ menuTx.setMatrix(surfaceControl, mMoveTransform, mTmpTransform);
if (pipLeash != null && t != null) {
- SurfaceParams pipParams = new SurfaceParams.Builder(pipLeash)
- .withMergeTransaction(t)
- .build();
- mApplier.scheduleApply(params, pipParams);
- } else {
- mApplier.scheduleApply(params);
+ // Merge the two transactions, vsyncId has been set on menuTx.
+ menuTx.merge(t);
}
+ menuTx.apply();
}
/**
@@ -353,36 +354,29 @@
return;
}
- if (!maybeCreateSyncApplier()) {
+ if (!checkPipMenuState()) {
return;
}
- SurfaceControl surfaceControl = getSurfaceControl();
- SurfaceParams params = new SurfaceParams.Builder(surfaceControl)
- .withWindowCrop(destinationBounds)
- .build();
+ final SurfaceControl surfaceControl = getSurfaceControl();
+ final SurfaceControl.Transaction menuTx =
+ mSurfaceControlTransactionFactory.getTransaction();
+ menuTx.setCrop(surfaceControl, destinationBounds);
if (pipLeash != null && t != null) {
- SurfaceParams pipParams = new SurfaceParams.Builder(pipLeash)
- .withMergeTransaction(t)
- .build();
- mApplier.scheduleApply(params, pipParams);
- } else {
- mApplier.scheduleApply(params);
+ // Merge the two transactions, vsyncId has been set on menuTx.
+ menuTx.merge(t);
}
+ menuTx.apply();
}
- private boolean maybeCreateSyncApplier() {
+ private boolean checkPipMenuState() {
if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: Not going to move PiP, either menu or its parent is not created.", TAG);
return false;
}
- if (mApplier == null) {
- mApplier = new SyncRtSurfaceTransactionApplier(mPipMenuView);
- }
-
- return mApplier != null;
+ return true;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
index 0f3ff36..8e3376f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
@@ -146,11 +146,8 @@
"%s: Failed to create input consumer, %s", TAG, e);
}
mMainExecutor.execute(() -> {
- // Choreographer.getSfInstance() must be called on the thread that the input event
- // receiver should be receiving events
- // TODO(b/222697646): remove getSfInstance usage and use vsyncId for transactions
mInputEventReceiver = new InputEventReceiver(inputChannel,
- Looper.myLooper(), Choreographer.getSfInstance());
+ Looper.myLooper(), Choreographer.getInstance());
if (mRegistrationListener != null) {
mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index abf1a95..89d85e4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -625,8 +625,7 @@
class PipResizeInputEventReceiver extends BatchedInputEventReceiver {
PipResizeInputEventReceiver(InputChannel channel, Looper looper) {
- // TODO(b/222697646): remove getSfInstance usage and use vsyncId for transactions
- super(channel, looper, Choreographer.getSfInstance());
+ super(channel, looper, Choreographer.getInstance());
}
public void onInputEvent(InputEvent event) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index b296151..93c7529 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -46,6 +46,8 @@
Consts.TAG_WM_SHELL),
WM_SHELL_SYSUI_EVENTS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_SHELL),
+ WM_SHELL_DESKTOP_MODE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM_SHELL),
TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest");
private final boolean mEnabled;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 7e83d2f..21fc01e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -25,6 +25,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -488,13 +489,6 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);
- // If split still not active, apply windows bounds first to avoid surface reset to
- // wrong pos by SurfaceAnimator from wms.
- // TODO(b/223325631): check is it still necessary after improve enter transition done.
- if (!mMainStage.isActive()) {
- updateWindowBounds(mSplitLayout, wct);
- }
-
wct.sendPendingIntent(intent, fillInIntent, options);
mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
}
@@ -641,7 +635,7 @@
wct.startTask(sideTaskId, sideOptions);
}
// Using legacy transitions, so we can't use blast sync since it conflicts.
- mTaskOrganizer.applyTransaction(wct);
+ mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
setDividerVisibility(true, t);
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
@@ -893,10 +887,13 @@
mShouldUpdateRecents = false;
mIsDividerRemoteAnimating = false;
+ mSplitLayout.getInvisibleBounds(mTempRect1);
if (childrenToTop == null) {
mSideStage.removeAllTasks(wct, false /* toTop */);
mMainStage.deactivate(wct, false /* toTop */);
wct.reorder(mRootTaskInfo.token, false /* onTop */);
+ wct.setForceTranslucent(mRootTaskInfo.token, true);
+ wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
onTransitionAnimationComplete();
} else {
// Expand to top side split as full screen for fading out decor animation and dismiss
@@ -907,27 +904,32 @@
? mSideStage : mMainStage;
tempFullStage.resetBounds(wct);
wct.setSmallestScreenWidthDp(tempFullStage.mRootTaskInfo.token,
- mRootTaskInfo.configuration.smallestScreenWidthDp);
+ SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
dismissStage.dismiss(wct, false /* toTop */);
}
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
t.setWindowCrop(mMainStage.mRootLeash, null)
.setWindowCrop(mSideStage.mRootLeash, null);
- t.setPosition(mMainStage.mRootLeash, 0, 0)
- .setPosition(mSideStage.mRootLeash, 0, 0);
t.hide(mMainStage.mDimLayer).hide(mSideStage.mDimLayer);
setDividerVisibility(false, t);
- // In this case, exit still under progress, fade out the split decor after first WCT
- // done and do remaining WCT after animation finished.
- if (childrenToTop != null) {
+ if (childrenToTop == null) {
+ t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.right);
+ } else {
+ // In this case, exit still under progress, fade out the split decor after first WCT
+ // done and do remaining WCT after animation finished.
childrenToTop.fadeOutDecor(() -> {
WindowContainerTransaction finishedWCT = new WindowContainerTransaction();
mIsExiting = false;
childrenToTop.dismiss(finishedWCT, true /* toTop */);
finishedWCT.reorder(mRootTaskInfo.token, false /* toTop */);
- mTaskOrganizer.applyTransaction(finishedWCT);
+ finishedWCT.setForceTranslucent(mRootTaskInfo.token, true);
+ finishedWCT.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
+ mSyncQueue.queue(finishedWCT);
+ mSyncQueue.runInSync(at -> {
+ at.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.right);
+ });
onTransitionAnimationComplete();
});
}
@@ -996,6 +998,7 @@
mMainStage.activate(wct, true /* includingTopTask */);
updateWindowBounds(mSplitLayout, wct);
wct.reorder(mRootTaskInfo.token, true);
+ wct.setForceTranslucent(mRootTaskInfo.token, false);
}
void finishEnterSplitScreen(SurfaceControl.Transaction t) {
@@ -1221,7 +1224,13 @@
// Make the stages adjacent to each other so they occlude what's behind them.
wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
- mTaskOrganizer.applyTransaction(wct);
+ wct.setForceTranslucent(mRootTaskInfo.token, true);
+ mSplitLayout.getInvisibleBounds(mTempRect1);
+ wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
+ mSyncQueue.queue(wct);
+ mSyncQueue.runInSync(t -> {
+ t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.top);
+ });
}
private void onRootTaskVanished() {
@@ -1377,10 +1386,17 @@
// TODO (b/238697912) : Add the validation to prevent entering non-recovered status
final WindowContainerTransaction wct = new WindowContainerTransaction();
mSplitLayout.init();
- prepareEnterSplitScreen(wct);
+ mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
+ mMainStage.activate(wct, true /* includingTopTask */);
+ updateWindowBounds(mSplitLayout, wct);
+ wct.reorder(mRootTaskInfo.token, true);
+ wct.setForceTranslucent(mRootTaskInfo.token, false);
mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t ->
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
+ mSyncQueue.runInSync(t -> {
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+
+ mSplitLayout.flingDividerToCenter();
+ });
}
if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
mShouldUpdateRecents = true;
@@ -1822,6 +1838,7 @@
// properly for the animation itself.
mSplitLayout.release();
mSplitLayout.resetDividerPosition();
+ mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 9335438..26d0ec6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -23,6 +23,7 @@
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.fixScale;
import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
@@ -167,10 +168,7 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "addHandler: Remote");
ContentResolver resolver = mContext.getContentResolver();
- mTransitionAnimationScaleSetting = Settings.Global.getFloat(resolver,
- Settings.Global.TRANSITION_ANIMATION_SCALE,
- mContext.getResources().getFloat(
- R.dimen.config_appTransitionAnimationDurationScaleDefault));
+ mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting();
dispatchAnimScaleSetting(mTransitionAnimationScaleSetting);
resolver.registerContentObserver(
@@ -185,6 +183,12 @@
}
}
+ private float getTransitionAnimationScaleSetting() {
+ return fixScale(Settings.Global.getFloat(mContext.getContentResolver(),
+ Settings.Global.TRANSITION_ANIMATION_SCALE, mContext.getResources().getFloat(
+ R.dimen.config_appTransitionAnimationDurationScaleDefault)));
+ }
+
public ShellTransitions asRemoteTransitions() {
return mImpl;
}
@@ -963,9 +967,7 @@
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
- mTransitionAnimationScaleSetting = Settings.Global.getFloat(
- mContext.getContentResolver(), Settings.Global.TRANSITION_ANIMATION_SCALE,
- mTransitionAnimationScaleSetting);
+ mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting();
mMainExecutor.execute(() -> dispatchAnimScaleSetting(mTransitionAnimationScaleSetting));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 98b5ee9..dc3deb1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -34,6 +34,7 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.desktopmode.DesktopModeConstants;
/**
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
@@ -163,7 +164,13 @@
View caption = mResult.mRootView.findViewById(R.id.caption);
caption.setOnTouchListener(mOnCaptionTouchListener);
View maximize = caption.findViewById(R.id.maximize_window);
- maximize.setOnClickListener(mOnCaptionButtonClickListener);
+ if (DesktopModeConstants.IS_FEATURE_ENABLED) {
+ // Hide maximize button when desktop mode is available
+ maximize.setVisibility(View.GONE);
+ } else {
+ maximize.setVisibility(View.VISIBLE);
+ maximize.setOnClickListener(mOnCaptionButtonClickListener);
+ }
View close = caption.findViewById(R.id.close_window);
close.setOnClickListener(mOnCaptionButtonClickListener);
View minimize = caption.findViewById(R.id.minimize_window);
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 506a4c0..5e64a06 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
@@ -248,7 +248,7 @@
lp.setTrustedOverlay();
if (mViewHost == null) {
mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
- mCaptionWindowManager, true);
+ mCaptionWindowManager);
mViewHost.setView(outResult.mRootView, lp);
} else {
mViewHost.relayout(lp);
@@ -345,9 +345,8 @@
}
interface SurfaceControlViewHostFactory {
- default SurfaceControlViewHost create(
- Context c, Display d, WindowlessWindowManager wmm, boolean useSfChoreographer) {
- return new SurfaceControlViewHost(c, d, wmm, useSfChoreographer);
+ default SurfaceControlViewHost create(Context c, Display d, WindowlessWindowManager wmm) {
+ return new SurfaceControlViewHost(c, d, wmm);
}
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index f865649..b29c436 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -16,9 +16,11 @@
package com.android.wm.shell;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -30,6 +32,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
@@ -38,9 +42,11 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.TaskInfo;
+import android.app.WindowConfiguration;
import android.content.LocusId;
import android.content.pm.ParceledListSlice;
import android.os.Binder;
@@ -53,6 +59,8 @@
import android.window.ITaskOrganizerController;
import android.window.TaskAppearedInfo;
import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+import android.window.WindowContainerTransaction.Change;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -628,6 +636,71 @@
verify(mTaskOrganizerController).restartTaskTopActivityProcessIfVisible(task1.token);
}
+ @Test
+ public void testPrepareClearBoundsForTasks() {
+ RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_UNDEFINED);
+ task1.displayId = 1;
+ MockToken token1 = new MockToken();
+ task1.token = token1.token();
+ mOrganizer.onTaskAppeared(task1, null);
+
+ RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_UNDEFINED);
+ task2.displayId = 1;
+ MockToken token2 = new MockToken();
+ task2.token = token2.token();
+ mOrganizer.onTaskAppeared(task2, null);
+
+ RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_UNDEFINED);
+ otherDisplayTask.displayId = 2;
+ MockToken otherDisplayToken = new MockToken();
+ otherDisplayTask.token = otherDisplayToken.token();
+ mOrganizer.onTaskAppeared(otherDisplayTask, null);
+
+ WindowContainerTransaction wct = mOrganizer.prepareClearBoundsForTasks(1);
+
+ assertEquals(wct.getChanges().size(), 2);
+ Change boundsChange1 = wct.getChanges().get(token1.binder());
+ assertNotNull(boundsChange1);
+ assertNotEquals(
+ (boundsChange1.getWindowSetMask() & WindowConfiguration.WINDOW_CONFIG_BOUNDS), 0);
+ assertTrue(boundsChange1.getConfiguration().windowConfiguration.getBounds().isEmpty());
+
+ Change boundsChange2 = wct.getChanges().get(token2.binder());
+ assertNotNull(boundsChange2);
+ assertNotEquals(
+ (boundsChange2.getWindowSetMask() & WindowConfiguration.WINDOW_CONFIG_BOUNDS), 0);
+ assertTrue(boundsChange2.getConfiguration().windowConfiguration.getBounds().isEmpty());
+ }
+
+ @Test
+ public void testPrepareClearFreeformForTasks() {
+ RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FREEFORM);
+ task1.displayId = 1;
+ MockToken token1 = new MockToken();
+ task1.token = token1.token();
+ mOrganizer.onTaskAppeared(task1, null);
+
+ RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_MULTI_WINDOW);
+ task2.displayId = 1;
+ MockToken token2 = new MockToken();
+ task2.token = token2.token();
+ mOrganizer.onTaskAppeared(task2, null);
+
+ RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_FREEFORM);
+ otherDisplayTask.displayId = 2;
+ MockToken otherDisplayToken = new MockToken();
+ otherDisplayTask.token = otherDisplayToken.token();
+ mOrganizer.onTaskAppeared(otherDisplayTask, null);
+
+ WindowContainerTransaction wct = mOrganizer.prepareClearFreeformForTasks(1);
+
+ // Only task with freeform windowing mode and the right display should be updated
+ assertEquals(wct.getChanges().size(), 1);
+ Change wmModeChange1 = wct.getChanges().get(token1.binder());
+ assertNotNull(wmModeChange1);
+ assertEquals(wmModeChange1.getWindowingMode(), WINDOWING_MODE_UNDEFINED);
+ }
+
private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
@@ -635,4 +708,22 @@
return taskInfo;
}
+ private static class MockToken {
+ private final WindowContainerToken mToken;
+ private final IBinder mBinder;
+
+ MockToken() {
+ mToken = mock(WindowContainerToken.class);
+ mBinder = mock(IBinder.class);
+ when(mToken.asBinder()).thenReturn(mBinder);
+ }
+
+ WindowContainerToken token() {
+ return mToken;
+ }
+
+ IBinder binder() {
+ return mBinder;
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
index 32f1587..ff1d2990 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
@@ -169,6 +169,7 @@
mTaskView.onTaskAppeared(mTaskInfo, mLeash);
verify(mViewListener).onTaskCreated(eq(mTaskInfo.taskId), any());
+ assertThat(mTaskView.isInitialized()).isTrue();
verify(mViewListener, never()).onTaskVisibilityChanged(anyInt(), anyBoolean());
}
@@ -178,6 +179,7 @@
mTaskView.surfaceCreated(mock(SurfaceHolder.class));
verify(mViewListener).onInitialized();
+ assertThat(mTaskView.isInitialized()).isTrue();
// No task, no visibility change
verify(mViewListener, never()).onTaskVisibilityChanged(anyInt(), anyBoolean());
}
@@ -189,6 +191,7 @@
mTaskView.surfaceCreated(mock(SurfaceHolder.class));
verify(mViewListener).onInitialized();
+ assertThat(mTaskView.isInitialized()).isTrue();
verify(mViewListener).onTaskVisibilityChanged(eq(mTaskInfo.taskId), eq(true));
}
@@ -223,6 +226,7 @@
verify(mOrganizer).removeListener(eq(mTaskView));
verify(mViewListener).onReleased();
+ assertThat(mTaskView.isInitialized()).isFalse();
}
@Test
@@ -270,6 +274,7 @@
verify(mViewListener).onTaskCreated(eq(mTaskInfo.taskId), any());
verify(mViewListener, never()).onInitialized();
+ assertThat(mTaskView.isInitialized()).isFalse();
// If there's no surface the task should be made invisible
verify(mViewListener).onTaskVisibilityChanged(eq(mTaskInfo.taskId), eq(false));
}
@@ -281,6 +286,7 @@
verify(mTaskViewTransitions, never()).setTaskViewVisible(any(), anyBoolean());
verify(mViewListener).onInitialized();
+ assertThat(mTaskView.isInitialized()).isTrue();
// No task, no visibility change
verify(mViewListener, never()).onTaskVisibilityChanged(anyInt(), anyBoolean());
}
@@ -353,6 +359,7 @@
verify(mOrganizer).removeListener(eq(mTaskView));
verify(mViewListener).onReleased();
+ assertThat(mTaskView.isInitialized()).isFalse();
verify(mTaskViewTransitions).removeTaskView(eq(mTaskView));
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 95725bb..695550d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -159,7 +159,8 @@
}
private void waitDividerFlingFinished() {
- verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), mRunnableCaptor.capture());
+ verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), anyInt(),
+ mRunnableCaptor.capture());
mRunnableCaptor.getValue().run();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
new file mode 100644
index 0000000..58f20da
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.WindowConfiguration;
+import android.os.Handler;
+import android.os.IBinder;
+import android.testing.AndroidTestingRunner;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+import android.window.WindowContainerTransaction.Change;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.RootDisplayAreaOrganizer;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.sysui.ShellInit;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DesktopModeControllerTest extends ShellTestCase {
+
+ @Mock
+ private ShellTaskOrganizer mShellTaskOrganizer;
+ @Mock
+ private RootDisplayAreaOrganizer mRootDisplayAreaOrganizer;
+ @Mock
+ private ShellExecutor mTestExecutor;
+ @Mock
+ private Handler mMockHandler;
+
+ private DesktopModeController mController;
+ private ShellInit mShellInit;
+
+ @Before
+ public void setUp() {
+ mShellInit = Mockito.spy(new ShellInit(mTestExecutor));
+
+ mController = new DesktopModeController(mContext, mShellInit, mShellTaskOrganizer,
+ mRootDisplayAreaOrganizer, mMockHandler);
+
+ mShellInit.init();
+ }
+
+ @Test
+ public void instantiate_addInitCallback() {
+ verify(mShellInit, times(1)).addInitCallback(any(), any());
+ }
+
+ @Test
+ public void testDesktopModeEnabled_taskWmClearedDisplaySetToFreeform() {
+ // Create a fake WCT to simulate setting task windowing mode to undefined
+ WindowContainerTransaction taskWct = new WindowContainerTransaction();
+ MockToken taskMockToken = new MockToken();
+ taskWct.setWindowingMode(taskMockToken.token(), WINDOWING_MODE_UNDEFINED);
+ when(mShellTaskOrganizer.prepareClearFreeformForTasks(mContext.getDisplayId())).thenReturn(
+ taskWct);
+
+ // Create a fake WCT to simulate setting display windowing mode to freeform
+ WindowContainerTransaction displayWct = new WindowContainerTransaction();
+ MockToken displayMockToken = new MockToken();
+ displayWct.setWindowingMode(displayMockToken.token(), WINDOWING_MODE_FREEFORM);
+ when(mRootDisplayAreaOrganizer.prepareWindowingModeChange(mContext.getDisplayId(),
+ WINDOWING_MODE_FREEFORM)).thenReturn(displayWct);
+
+ // The test
+ mController.updateDesktopModeEnabled(true);
+
+ ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
+ WindowContainerTransaction.class);
+ verify(mRootDisplayAreaOrganizer).applyTransaction(arg.capture());
+
+ // WCT should have 2 changes - clear task wm mode and set display wm mode
+ WindowContainerTransaction wct = arg.getValue();
+ assertThat(wct.getChanges()).hasSize(2);
+
+ // Verify executed WCT has a change for setting task windowing mode to undefined
+ Change taskWmModeChange = wct.getChanges().get(taskMockToken.binder());
+ assertThat(taskWmModeChange).isNotNull();
+ assertThat(taskWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
+
+ // Verify executed WCT has a change for setting display windowing mode to freeform
+ Change displayWmModeChange = wct.getChanges().get(displayMockToken.binder());
+ assertThat(displayWmModeChange).isNotNull();
+ assertThat(displayWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testDesktopModeDisabled_taskWmAndBoundsClearedDisplaySetToFullscreen() {
+ // Create a fake WCT to simulate setting task windowing mode to undefined
+ WindowContainerTransaction taskWmWct = new WindowContainerTransaction();
+ MockToken taskWmMockToken = new MockToken();
+ taskWmWct.setWindowingMode(taskWmMockToken.token(), WINDOWING_MODE_UNDEFINED);
+ when(mShellTaskOrganizer.prepareClearFreeformForTasks(mContext.getDisplayId())).thenReturn(
+ taskWmWct);
+
+ // Create a fake WCT to simulate clearing task bounds
+ WindowContainerTransaction taskBoundsWct = new WindowContainerTransaction();
+ MockToken taskBoundsMockToken = new MockToken();
+ taskBoundsWct.setBounds(taskBoundsMockToken.token(), null);
+ when(mShellTaskOrganizer.prepareClearBoundsForTasks(mContext.getDisplayId())).thenReturn(
+ taskBoundsWct);
+
+ // Create a fake WCT to simulate setting display windowing mode to fullscreen
+ WindowContainerTransaction displayWct = new WindowContainerTransaction();
+ MockToken displayMockToken = new MockToken();
+ displayWct.setWindowingMode(displayMockToken.token(), WINDOWING_MODE_FULLSCREEN);
+ when(mRootDisplayAreaOrganizer.prepareWindowingModeChange(mContext.getDisplayId(),
+ WINDOWING_MODE_FULLSCREEN)).thenReturn(displayWct);
+
+ // The test
+ mController.updateDesktopModeEnabled(false);
+
+ ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
+ WindowContainerTransaction.class);
+ verify(mRootDisplayAreaOrganizer).applyTransaction(arg.capture());
+
+ // WCT should have 3 changes - clear task wm mode and bounds and set display wm mode
+ WindowContainerTransaction wct = arg.getValue();
+ assertThat(wct.getChanges()).hasSize(3);
+
+ // Verify executed WCT has a change for setting task windowing mode to undefined
+ Change taskWmModeChange = wct.getChanges().get(taskWmMockToken.binder());
+ assertThat(taskWmModeChange).isNotNull();
+ assertThat(taskWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
+
+ // Verify executed WCT has a change for clearing task bounds
+ Change taskBoundsChange = wct.getChanges().get(taskBoundsMockToken.binder());
+ assertThat(taskBoundsChange).isNotNull();
+ assertThat(taskBoundsChange.getWindowSetMask()
+ & WindowConfiguration.WINDOW_CONFIG_BOUNDS).isNotEqualTo(0);
+ assertThat(taskBoundsChange.getConfiguration().windowConfiguration.getBounds().isEmpty())
+ .isTrue();
+
+ // Verify executed WCT has a change for setting display windowing mode to fullscreen
+ Change displayWmModeChange = wct.getChanges().get(displayMockToken.binder());
+ assertThat(displayWmModeChange).isNotNull();
+ assertThat(displayWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_FULLSCREEN);
+ }
+
+ private static class MockToken {
+ private final WindowContainerToken mToken;
+ private final IBinder mBinder;
+
+ MockToken() {
+ mToken = mock(WindowContainerToken.class);
+ mBinder = mock(IBinder.class);
+ when(mToken.asBinder()).thenReturn(mBinder);
+ }
+
+ WindowContainerToken token() {
+ return mToken;
+ }
+
+ IBinder binder() {
+ return mBinder;
+ }
+ }
+}
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 226843e..e11be31 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
@@ -24,7 +24,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
@@ -107,7 +106,7 @@
mMockSurfaceControlFinishT = createMockSurfaceControlTransaction();
doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
- .create(any(), any(), any(), anyBoolean());
+ .create(any(), any(), any());
}
@Test
@@ -148,8 +147,7 @@
verify(decorContainerSurfaceBuilder, never()).build();
verify(taskBackgroundSurfaceBuilder, never()).build();
- verify(mMockSurfaceControlViewHostFactory, never())
- .create(any(), any(), any(), anyBoolean());
+ verify(mMockSurfaceControlViewHostFactory, never()).create(any(), any(), any());
verify(mMockSurfaceControlFinishT).hide(taskSurface);
@@ -207,8 +205,7 @@
verify(mMockSurfaceControlStartT).setLayer(taskBackgroundSurface, -1);
verify(mMockSurfaceControlStartT).show(taskBackgroundSurface);
- verify(mMockSurfaceControlViewHostFactory)
- .create(any(), eq(defaultDisplay), any(), anyBoolean());
+ verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any());
verify(mMockSurfaceControlViewHost)
.setView(same(mMockView),
argThat(lp -> lp.height == 64
@@ -326,8 +323,7 @@
verify(mMockDisplayController).removeDisplayWindowListener(same(listener));
assertThat(mRelayoutResult.mRootView).isSameInstanceAs(mMockView);
- verify(mMockSurfaceControlViewHostFactory)
- .create(any(), eq(mockDisplay), any(), anyBoolean());
+ verify(mMockSurfaceControlViewHostFactory).create(any(), eq(mockDisplay), any());
verify(mMockSurfaceControlViewHost).setView(same(mMockView), any());
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 8756f1e..c08f5a2 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -45,6 +45,7 @@
import java.nio.ReadOnlyBufferException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -1803,7 +1804,7 @@
synchronized(mBufferLock) {
switch (mBufferMode) {
case BUFFER_MODE_LEGACY:
- validateInputByteBuffer(mCachedInputBuffers, index);
+ validateInputByteBufferLocked(mCachedInputBuffers, index);
break;
case BUFFER_MODE_BLOCK:
while (mQueueRequests.size() <= index) {
@@ -1832,7 +1833,7 @@
synchronized(mBufferLock) {
switch (mBufferMode) {
case BUFFER_MODE_LEGACY:
- validateOutputByteBuffer(mCachedOutputBuffers, index, info);
+ validateOutputByteBufferLocked(mCachedOutputBuffers, index, info);
break;
case BUFFER_MODE_BLOCK:
while (mOutputFrames.size() <= index) {
@@ -2320,10 +2321,6 @@
*/
public final void start() {
native_start();
- synchronized(mBufferLock) {
- cacheBuffers(true /* input */);
- cacheBuffers(false /* input */);
- }
}
private native final void native_start();
@@ -2380,8 +2377,10 @@
*/
public final void flush() {
synchronized(mBufferLock) {
- invalidateByteBuffers(mCachedInputBuffers);
- invalidateByteBuffers(mCachedOutputBuffers);
+ invalidateByteBuffersLocked(mCachedInputBuffers);
+ invalidateByteBuffersLocked(mCachedOutputBuffers);
+ mValidInputIndices.clear();
+ mValidOutputIndices.clear();
mDequeuedInputBuffers.clear();
mDequeuedOutputBuffers.clear();
}
@@ -2665,14 +2664,14 @@
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please use getQueueRequest() to queue buffers");
}
- invalidateByteBuffer(mCachedInputBuffers, index);
+ invalidateByteBufferLocked(mCachedInputBuffers, index, true /* input */);
mDequeuedInputBuffers.remove(index);
}
try {
native_queueInputBuffer(
index, offset, size, presentationTimeUs, flags);
} catch (CryptoException | IllegalStateException e) {
- revalidateByteBuffer(mCachedInputBuffers, index);
+ revalidateByteBuffer(mCachedInputBuffers, index, true /* input */);
throw e;
}
}
@@ -2935,14 +2934,14 @@
+ "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ "Please use getQueueRequest() to queue buffers");
}
- invalidateByteBuffer(mCachedInputBuffers, index);
+ invalidateByteBufferLocked(mCachedInputBuffers, index, true /* input */);
mDequeuedInputBuffers.remove(index);
}
try {
native_queueSecureInputBuffer(
index, offset, info, presentationTimeUs, flags);
} catch (CryptoException | IllegalStateException e) {
- revalidateByteBuffer(mCachedInputBuffers, index);
+ revalidateByteBuffer(mCachedInputBuffers, index, true /* input */);
throw e;
}
}
@@ -2976,7 +2975,7 @@
int res = native_dequeueInputBuffer(timeoutUs);
if (res >= 0) {
synchronized(mBufferLock) {
- validateInputByteBuffer(mCachedInputBuffers, res);
+ validateInputByteBufferLocked(mCachedInputBuffers, res);
}
}
return res;
@@ -3573,10 +3572,10 @@
int res = native_dequeueOutputBuffer(info, timeoutUs);
synchronized (mBufferLock) {
if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
- cacheBuffers(false /* input */);
+ cacheBuffersLocked(false /* input */);
} else if (res >= 0) {
- validateOutputByteBuffer(mCachedOutputBuffers, res, info);
- if (mHasSurface) {
+ validateOutputByteBufferLocked(mCachedOutputBuffers, res, info);
+ if (mHasSurface || mCachedOutputBuffers == null) {
mDequeuedOutputInfos.put(res, info.dup());
}
}
@@ -3670,9 +3669,9 @@
synchronized(mBufferLock) {
switch (mBufferMode) {
case BUFFER_MODE_LEGACY:
- invalidateByteBuffer(mCachedOutputBuffers, index);
+ invalidateByteBufferLocked(mCachedOutputBuffers, index, false /* input */);
mDequeuedOutputBuffers.remove(index);
- if (mHasSurface) {
+ if (mHasSurface || mCachedOutputBuffers == null) {
info = mDequeuedOutputInfos.remove(index);
}
break;
@@ -3824,15 +3823,24 @@
private ByteBuffer[] mCachedInputBuffers;
private ByteBuffer[] mCachedOutputBuffers;
+ private BitSet mValidInputIndices = new BitSet();
+ private BitSet mValidOutputIndices = new BitSet();
+
private final BufferMap mDequeuedInputBuffers = new BufferMap();
private final BufferMap mDequeuedOutputBuffers = new BufferMap();
private final Map<Integer, BufferInfo> mDequeuedOutputInfos =
new HashMap<Integer, BufferInfo>();
final private Object mBufferLock;
- private final void invalidateByteBuffer(
- @Nullable ByteBuffer[] buffers, int index) {
- if (buffers != null && index >= 0 && index < buffers.length) {
+ private void invalidateByteBufferLocked(
+ @Nullable ByteBuffer[] buffers, int index, boolean input) {
+ if (buffers == null) {
+ if (index < 0) {
+ throw new IllegalStateException("index is negative (" + index + ")");
+ }
+ BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
+ indices.clear(index);
+ } else if (index >= 0 && index < buffers.length) {
ByteBuffer buffer = buffers[index];
if (buffer != null) {
buffer.setAccessible(false);
@@ -3840,9 +3848,14 @@
}
}
- private final void validateInputByteBuffer(
+ private void validateInputByteBufferLocked(
@Nullable ByteBuffer[] buffers, int index) {
- if (buffers != null && index >= 0 && index < buffers.length) {
+ if (buffers == null) {
+ if (index < 0) {
+ throw new IllegalStateException("index is negative (" + index + ")");
+ }
+ mValidInputIndices.set(index);
+ } else if (index >= 0 && index < buffers.length) {
ByteBuffer buffer = buffers[index];
if (buffer != null) {
buffer.setAccessible(true);
@@ -3851,10 +3864,16 @@
}
}
- private final void revalidateByteBuffer(
- @Nullable ByteBuffer[] buffers, int index) {
+ private void revalidateByteBuffer(
+ @Nullable ByteBuffer[] buffers, int index, boolean input) {
synchronized(mBufferLock) {
- if (buffers != null && index >= 0 && index < buffers.length) {
+ if (buffers == null) {
+ if (index < 0) {
+ throw new IllegalStateException("index is negative (" + index + ")");
+ }
+ BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
+ indices.set(index);
+ } else if (index >= 0 && index < buffers.length) {
ByteBuffer buffer = buffers[index];
if (buffer != null) {
buffer.setAccessible(true);
@@ -3863,9 +3882,14 @@
}
}
- private final void validateOutputByteBuffer(
+ private void validateOutputByteBufferLocked(
@Nullable ByteBuffer[] buffers, int index, @NonNull BufferInfo info) {
- if (buffers != null && index >= 0 && index < buffers.length) {
+ if (buffers == null) {
+ if (index < 0) {
+ throw new IllegalStateException("index is negative (" + index + ")");
+ }
+ mValidOutputIndices.set(index);
+ } else if (index >= 0 && index < buffers.length) {
ByteBuffer buffer = buffers[index];
if (buffer != null) {
buffer.setAccessible(true);
@@ -3874,7 +3898,7 @@
}
}
- private final void invalidateByteBuffers(@Nullable ByteBuffer[] buffers) {
+ private void invalidateByteBuffersLocked(@Nullable ByteBuffer[] buffers) {
if (buffers != null) {
for (ByteBuffer buffer: buffers) {
if (buffer != null) {
@@ -3884,27 +3908,29 @@
}
}
- private final void freeByteBuffer(@Nullable ByteBuffer buffer) {
+ private void freeByteBufferLocked(@Nullable ByteBuffer buffer) {
if (buffer != null /* && buffer.isDirect() */) {
// all of our ByteBuffers are direct
java.nio.NioUtils.freeDirectBuffer(buffer);
}
}
- private final void freeByteBuffers(@Nullable ByteBuffer[] buffers) {
+ private void freeByteBuffersLocked(@Nullable ByteBuffer[] buffers) {
if (buffers != null) {
for (ByteBuffer buffer: buffers) {
- freeByteBuffer(buffer);
+ freeByteBufferLocked(buffer);
}
}
}
- private final void freeAllTrackedBuffers() {
+ private void freeAllTrackedBuffers() {
synchronized(mBufferLock) {
- freeByteBuffers(mCachedInputBuffers);
- freeByteBuffers(mCachedOutputBuffers);
+ freeByteBuffersLocked(mCachedInputBuffers);
+ freeByteBuffersLocked(mCachedOutputBuffers);
mCachedInputBuffers = null;
mCachedOutputBuffers = null;
+ mValidInputIndices.clear();
+ mValidOutputIndices.clear();
mDequeuedInputBuffers.clear();
mDequeuedOutputBuffers.clear();
mQueueRequests.clear();
@@ -3912,14 +3938,31 @@
}
}
- private final void cacheBuffers(boolean input) {
+ private void cacheBuffersLocked(boolean input) {
ByteBuffer[] buffers = null;
try {
buffers = getBuffers(input);
- invalidateByteBuffers(buffers);
+ invalidateByteBuffersLocked(buffers);
} catch (IllegalStateException e) {
// we don't get buffers in async mode
}
+ if (buffers != null) {
+ BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
+ for (int i = 0; i < buffers.length; ++i) {
+ ByteBuffer buffer = buffers[i];
+ if (buffer == null || !indices.get(i)) {
+ continue;
+ }
+ buffer.setAccessible(true);
+ if (!input) {
+ BufferInfo info = mDequeuedOutputInfos.get(i);
+ if (info != null) {
+ buffer.limit(info.offset + info.size).position(info.offset);
+ }
+ }
+ }
+ indices.clear();
+ }
if (input) {
mCachedInputBuffers = buffers;
} else {
@@ -3955,6 +3998,9 @@
+ "objects and attach to QueueRequest objects.");
}
if (mCachedInputBuffers == null) {
+ cacheBuffersLocked(true /* input */);
+ }
+ if (mCachedInputBuffers == null) {
throw new IllegalStateException();
}
// FIXME: check codec status
@@ -3993,6 +4039,9 @@
+ "Please use getOutputFrame to get output frames.");
}
if (mCachedOutputBuffers == null) {
+ cacheBuffersLocked(false /* input */);
+ }
+ if (mCachedOutputBuffers == null) {
throw new IllegalStateException();
}
// FIXME: check codec status
@@ -4030,7 +4079,7 @@
}
ByteBuffer newBuffer = getBuffer(true /* input */, index);
synchronized (mBufferLock) {
- invalidateByteBuffer(mCachedInputBuffers, index);
+ invalidateByteBufferLocked(mCachedInputBuffers, index, true /* input */);
mDequeuedInputBuffers.put(index, newBuffer);
}
return newBuffer;
@@ -4067,7 +4116,7 @@
}
Image newImage = getImage(true /* input */, index);
synchronized (mBufferLock) {
- invalidateByteBuffer(mCachedInputBuffers, index);
+ invalidateByteBufferLocked(mCachedInputBuffers, index, true /* input */);
mDequeuedInputBuffers.put(index, newImage);
}
return newImage;
@@ -4103,7 +4152,7 @@
}
ByteBuffer newBuffer = getBuffer(false /* input */, index);
synchronized (mBufferLock) {
- invalidateByteBuffer(mCachedOutputBuffers, index);
+ invalidateByteBufferLocked(mCachedOutputBuffers, index, false /* input */);
mDequeuedOutputBuffers.put(index, newBuffer);
}
return newBuffer;
@@ -4138,7 +4187,7 @@
}
Image newImage = getImage(false /* input */, index);
synchronized (mBufferLock) {
- invalidateByteBuffer(mCachedOutputBuffers, index);
+ invalidateByteBufferLocked(mCachedOutputBuffers, index, false /* input */);
mDequeuedOutputBuffers.put(index, newImage);
}
return newImage;
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index dd36b49..481d26d 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-oudio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD oudio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Gehoortoestelle"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE-oudio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Gekoppel aan gehoortoestelle"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Gekoppel aan LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Gekoppel aan LE-oudio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Gekoppel aan media-oudio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Gekoppel aan foonoudio"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Gekoppel aan lêeroordragbediener"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Maak die groottes van alle aktiwiteite verstelbaar vir veelvuldige vensters, ongeag manifeswaardes."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Aktiveer vormvrye vensters"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktiveer steun vir eksperimentele vormvrye vensters."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Rekenaarmodus"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Werkskerm-rugsteunwagwoord"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Volle rekenaarrugsteune word nie tans beskerm nie"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tik om die wagwoord vir volledige rekenaarrugsteune te verander of te verwyder"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> oor tot vol"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> oor tot vol"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laaiproses word tydelik beperk"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laai"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laai tans vinnig"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Laai tans stadig"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Laai tans draadloos"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Laaidok"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Laai nie"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Gekoppel, laai nie"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Gelaai"</string>
diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml
index a900d13..7bef7fa 100644
--- a/packages/SettingsLib/res/values-am/arrays.xml
+++ b/packages/SettingsLib/res/values-am/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"የስርዓቱን ምርጫ (ነባሪ) ተጠቀም"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ኦዲዮ"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ኦዲዮ"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"የስርዓቱን ምርጫ (ነባሪ) ተጠቀም"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ኦዲዮ"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ኦዲዮ"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"የስርዓቱን ምርጫ (ነባሪ) ተጠቀም"</item>
<item msgid="8003118270854840095">"44.1 ኪኸ"</item>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 2018778..9a51181 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"ኤችዲ ኦዲዮ፦ <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"ኤችዲ ኦዲዮ"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"አጋዥ መስሚያዎች"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE ኦዲዮ"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ከአጋዥ መስሚያዎች ጋር ተገናኝቷል"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"ከLE_AUDIO ጋር ተገናኝቷል"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"ከLE ኦዲዮ ጋር ተገናኝቷል"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ወደ ማህደረ መረጃ አውዲዮ ተያይዟል"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ወደ ስልክ አውዲዮ ተያይዟል"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ወደ ፋይል ዝውውር አገልጋይ ተያይዟል"</string>
@@ -183,21 +183,21 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"ተጠቃሚ፦ <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"አንዳንድ ነባሪዎ ተዘጋጅተዋል"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"ምንም ነባሪዎች አልተዘጋጁም"</string>
- <string name="tts_settings" msgid="8130616705989351312">"ፅሁፍ-ወደ-ንግግር ቅንብሮች"</string>
+ <string name="tts_settings" msgid="8130616705989351312">"ጽሁፍ-ወደ-ንግግር ቅንብሮች"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"የፅሁፍ- ወደ- ንግግር ውፅዓት"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">" የንግግር ደረጃ"</string>
- <string name="tts_default_rate_summary" msgid="3781937042151716987">"የተነገረበትን ፅሁፍ አፍጥን"</string>
+ <string name="tts_default_rate_summary" msgid="3781937042151716987">"የተነገረበትን ጽሁፍ አፍጥን"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"ቅላፄ"</string>
<string name="tts_default_pitch_summary" msgid="9132719475281551884">"በሲንተሲስ በተሠራው ድምፅ ላይ ተፅዕኖ ያሳድራል"</string>
<string name="tts_default_lang_title" msgid="4698933575028098940">"ቋንቋ"</string>
<string name="tts_lang_use_system" msgid="6312945299804012406">"የስርዓት ቋንቋ ተጠቀም"</string>
<string name="tts_lang_not_selected" msgid="7927823081096056147">"ቋንቋ አልተመረጠም"</string>
- <string name="tts_default_lang_summary" msgid="9042620014800063470">"ለሚነገረው ፅሁፍ ቋንቋ-ተኮር ድምፅ አዘጋጅ"</string>
+ <string name="tts_default_lang_summary" msgid="9042620014800063470">"ለሚነገረው ጽሁፍ ቋንቋ-ተኮር ድምፅ አዘጋጅ"</string>
<string name="tts_play_example_title" msgid="1599468547216481684">"ምሳሌውን አዳምጥ"</string>
<string name="tts_play_example_summary" msgid="634044730710636383">"አጭር የንግግር ልምምድ ማሳያ አጫውት"</string>
<string name="tts_install_data_title" msgid="1829942496472751703">"የድምፅ ውሂብ ጫን"</string>
<string name="tts_install_data_summary" msgid="3608874324992243851">"ለንግግር ልምምድ የሚጠየቀውን የድምፅ ውሂብ ጫን"</string>
- <string name="tts_engine_security_warning" msgid="3372432853837988146">"ይህ የንግግር ልምምድ አንቀሳቃሽ የሚነገረውን ፅሁፍ ሁሉ እንደ ይለፍ ቃል እና የዱቤ ካርድ ቁጥሮች፣ የግል ውሂብ ጨምሮ ለመሰብሰብ ይችል ይሆናል። ከ <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> አንቀሳቃሽ ይመጣል። የዚህን የንግግር ልምምድ አንቀሳቃሽ አጠቃቀም ይንቃ?"</string>
+ <string name="tts_engine_security_warning" msgid="3372432853837988146">"ይህ የንግግር ልምምድ አንቀሳቃሽ የሚነገረውን ጽሁፍ ሁሉ እንደ ይለፍ ቃል እና የዱቤ ካርድ ቁጥሮች፣ የግል ውሂብ ጨምሮ ለመሰብሰብ ይችል ይሆናል። ከ <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> አንቀሳቃሽ ይመጣል። የዚህን የንግግር ልምምድ አንቀሳቃሽ አጠቃቀም ይንቃ?"</string>
<string name="tts_engine_network_required" msgid="8722087649733906851">"ይህ ቋንቋ የጽሑፍ-ወደ-ንግግር ውጽዓት እንዲኖረው የሚሰራ የአውታረ መረብ ግንኙነት ያስፈልገዋል።"</string>
<string name="tts_default_sample_string" msgid="6388016028292967973">"ይህ የተሰራ ንግግር ምሳሌ ነው"</string>
<string name="tts_status_title" msgid="8190784181389278640">"የነባሪ ቋንቋ ሁኔታ"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"የዝርዝር ሰነድ እሴቶች ምንም ይሁኑ ምን ለበርካታ መስኮቶች ሁሉንም እንቅስቃሴዎች መጠናቸው የሚቀየሩ እንዲሆኑ ያደርጋቸዋል።"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"የነጻ ቅርጽ መስኮቶችን ያንቁ"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"የሙከራ ነጻ መልክ መስኮቶች ድጋፍን አንቃ"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"የዴስክቶፕ ሁነታ"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"የዴስክቶፕ መጠባበቂያ ይለፍ ቃል"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ዴስክቶፕ ሙሉ ምትኬዎች በአሁኑ ሰዓት አልተጠበቁም"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"የዴስክቶፕ ሙሉ ምትኬዎች የይለፍ ቃሉን ለመለወጥ ወይም ለማስወገድ ነካ ያድርጉ"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"እስኪሞላ ድረስ <xliff:g id="TIME">%1$s</xliff:g> ይቀራል"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - እስኪሞላ ድረስ <xliff:g id="TIME">%2$s</xliff:g> ይቀራል"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - ኃይል መሙላት ለጊዜው ተገድቧል"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"ያልታወቀ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ኃይል በመሙላት ላይ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ኃይል በፍጥነት በመሙላት ላይ"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ኃይል በዝግታ በመሙላት ላይ"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"በገመድ-አልባ ኃይል በመሙላት ላይ"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"የኃይል መሙያ መትከያ"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ባትሪ እየሞላ አይደለም"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ተገናኝቷል፣ ኃይል በመሙላት ላይ አይደለም"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ባትሪ ሞልቷል"</string>
@@ -514,7 +517,7 @@
<string name="active_input_method_subtypes" msgid="4232680535471633046">"የገባሪ ግቤት ዘዴ"</string>
<string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"የሥርዓት ቋንቋዎችን ይጠቀሙ"</string>
<string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"የ<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> ቅንብሮች መክፈት አልተሳካም"</string>
- <string name="ime_security_warning" msgid="6547562217880551450">"ይህ ግቤት ስልት የሚትተይበውን ፅሁፍ ሁሉ፣ እንደይለፍ ቃል እና የብድር ካርድ ጨምሮ የግል ውሂብ ምናልባት መሰብሰብ ይችላል። ከትግበራው ይመጣል። <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> ይህን ግቤት ስልትይጠቀም?"</string>
+ <string name="ime_security_warning" msgid="6547562217880551450">"ይህ ግቤት ስልት የሚትተይበውን ጽሁፍ ሁሉ፣ እንደይለፍ ቃል እና የብድር ካርድ ጨምሮ የግል ውሂብ ምናልባት መሰብሰብ ይችላል። ከትግበራው ይመጣል። <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> ይህን ግቤት ስልትይጠቀም?"</string>
<string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"ማስታወሻ፦ እንደገና ከማስነሳት በኋላ ይህ መተግበሪያ ስልክዎን እስከሚከፍቱት ድረስ ሊጀምር አይችልም"</string>
<string name="ims_reg_title" msgid="8197592958123671062">"የIMS ምዝገባ ቀን"</string>
<string name="ims_reg_status_registered" msgid="884916398194885457">"የተመዘገበ"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"የአየር ጥራት"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"የCast መረጃ"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"የቤት ውስጥ ቁጥጥሮች"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"የመገለጫ ሥዕል ይምረጡ"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ነባሪ የተጠቃሚ አዶ"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"አካላዊ ቁልፍ ሰሌዳ"</string>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index 8f7d7d2..0720cf5 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"استخدام اختيار النظام (تلقائي)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"استخدام اختيار النظام (تلقائي)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"استخدام اختيار النظام (تلقائي)"</item>
<item msgid="8003118270854840095">"44.1 كيلو هرتز"</item>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 65c8edc..086956b 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"صوت عالي الدقة: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"صوت عالي الدقة"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"سماعات الأذن الطبية"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"تمّ التوصيل بسماعات الأذن الطبية"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"متصل بـ LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"متصل بـ LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"متصل بالإعدادات الصوتية للوسائط"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"متصل بالإعدادات الصوتية للهاتف"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"متصل بخادم نقل الملف"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"السماح بتغيير حجم جميع الأنشطة لتناسب تعدد النوافذ، بغض النظر عن قيم البيان"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"تفعيل النوافذ الحرة"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"إتاحة استخدام النوافذ الحرة التجريبية"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"وضع سطح المكتب"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"كلمة مرور احتياطية للكمبيوتر"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"النُسخ الاحتياطية الكاملة لسطح المكتب غير محمية في الوقت الحالي."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"انقر لتغيير كلمة مرور النسخ الاحتياطية الكاملة لسطح المكتب أو إزالتها."</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"يتبقّى <xliff:g id="TIME">%1$s</xliff:g> حتى اكتمال شحن البطارية."</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - يتبقّى <xliff:g id="TIME">%2$s</xliff:g> حتى اكتمال شحن البطارية."</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - الشحن محدود مؤقتًا"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"غير معروف"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"جارٍ الشحن"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"جارٍ الشحن سريعًا"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"جارٍ الشحن ببطء"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"جارٍ الشحن لاسلكيًا"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"وحدة الإرساء للشحن"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"لا يتم الشحن"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"الجهاز متصل بالشاحن، ولا يتم الشحن."</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"مشحونة"</string>
@@ -590,7 +593,7 @@
<string name="add_user_failed" msgid="4809887794313944872">"تعذّر إنشاء مستخدم جديد."</string>
<string name="add_guest_failed" msgid="8074548434469843443">"تعذّر إنشاء جلسة ضيف جديدة."</string>
<string name="user_nickname" msgid="262624187455825083">"اللقب"</string>
- <string name="user_add_user" msgid="7876449291500212468">"إضافة حساب مستخدم"</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_reset_guest" msgid="6110013010356013758">"إعادة ضبط جلسة الضيف"</string>
@@ -600,7 +603,7 @@
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"إزالة"</string>
<string name="guest_resetting" msgid="7822120170191509566">"جارٍ إعادة ضبط جلسة الضيف…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"هل تريد إعادة ضبط جلسة الضيف؟"</string>
- <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"سيؤدي إجراء إعادة الضبط إلى بدء جلسة ضيف جديدة وحذف جميع التطبيقات والبيانات من الجلسة الحالية."</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ستؤدي إعادة الضبط إلى بدء جلسة ضيف جديدة وحذف جميع التطبيقات والبيانات من الجلسة الحالية."</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"هل تريد الخروج من وضع الضيف؟"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"سيؤدي الخروج من وضع الضيف إلى حذف التطبيقات والبيانات من جلسة الضيف الحالية."</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"خروج"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"جودة الهواء"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"معلومات البث"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"إدارة آلية للمنزل"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"اختيار صورة الملف الشخصي"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"رمز المستخدم التلقائي"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"لوحة مفاتيح خارجية"</string>
diff --git a/packages/SettingsLib/res/values-as/arrays.xml b/packages/SettingsLib/res/values-as/arrays.xml
index 4c879d0..cbacce8 100644
--- a/packages/SettingsLib/res/values-as/arrays.xml
+++ b/packages/SettingsLib/res/values-as/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"ছিষ্টেমৰ বাছনি ব্যৱহাৰ কৰক (ডিফ\'ল্ট)"</item>
+ <item msgid="4055460186095649420">"এছবিচি"</item>
+ <item msgid="720249083677397051">"এএচি"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> অডিঅ\'"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> অডিঅ’"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"ছিষ্টেমৰ বাছনি ব্যৱহাৰ কৰক (ডিফ\'ল্ট)"</item>
+ <item msgid="9024885861221697796">"এছবিচি"</item>
+ <item msgid="4688890470703790013">"এএচি"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> অডিঅ’"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> অডিঅ’"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"ছিষ্টেমৰ বাছনি ব্যৱহাৰ কৰক (ডিফ\'ল্ট)"</item>
<item msgid="8003118270854840095">"৪৪.১ কিল\'হাৰ্টজ"</item>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 402c615e..9e0f910 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -121,13 +121,13 @@
<string name="bluetooth_profile_pbap_summary" msgid="6466456791354759132">"সম্পৰ্কসূচী আৰু কলৰ ইতিহাস শ্বেয়াৰ কৰাৰ বাবে ব্যৱহাৰ কৰক"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ইণ্টাৰনেট সংযোগ শ্বেয়াৰ"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"পাঠ বাৰ্তা"</string>
- <string name="bluetooth_profile_sap" msgid="8304170950447934386">"ছিম প্ৰৱেশ"</string>
+ <string name="bluetooth_profile_sap" msgid="8304170950447934386">"ছিমৰ এক্সেছ"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"এইচ্ছডি অডি\'অ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"এইচ্ছডি অডিঅ’"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"শ্ৰৱণ যন্ত্ৰ"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE অডিঅ’"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"শ্ৰৱণ যন্ত্ৰলৈ সংযোগ কৰা হৈছে"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIOৰ সৈতে সংযোগ কৰক"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE অডিঅ’ৰ সৈতে সংযোগ কৰক"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"মিডিয়া অডিঅ’লৈ সংযোগ হৈছে"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ফ’ন অডিঅ\'ৰ লগত সংযোগ কৰা হ’ল"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ফাইল ট্ৰান্সফাৰ ছাৰ্ভাৰৰ সৈতে সংযোজিত হৈ আছে"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"মেনিফেষ্টৰ মান যিয়েই নহওক, মাল্টি-ৱিণ্ডৰ বাবে আটাইবোৰ কাৰ্যকলাপৰ আকাৰ সলনি কৰিব পৰা কৰক।"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"ফ্ৰিফৰ্ম ৱিণ্ড\'জ সক্ষম কৰক"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"পৰীক্ষামূলক ফ্ৰী-ফৰ্ম ৱিণ্ড’বোৰৰ বাবে সহায়তা সক্ষম কৰক৷"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"ডেস্কটপ ম’ড"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ডেস্কটপ বেকআপ পাছৱৰ্ড"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ডেস্কটপৰ পূৰ্ণ বেকআপ এতিয়ালৈকে সংৰক্ষিত অৱস্থাত নাই"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ডেস্কটপ সম্পূৰ্ণ বেকআপৰ বাবে পাছৱৰ্ডটো সলনি কৰিবলৈ বা আঁতৰাবলৈ টিপক"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"সম্পূৰ্ণ হ’বলৈ <xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"সম্পূৰ্ণ হ’বলৈ <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> বাকী আছে"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> • চাৰ্জ কৰাটো সাময়িকভাৱে সীমিত কৰা হৈছে"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"অজ্ঞাত"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"চাৰ্জ কৰি থকা হৈছে"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্ৰুততাৰে চাৰ্জ হৈছে"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"লাহে লাহে চাৰ্জ হৈছে"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"বেতাঁৰৰ মাধ্যমেৰে চাৰ্জ হৈ আছে"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"চাৰ্জিং ড’ক"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"চ্চাৰ্জ কৰা নাই"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"সংযোগ হৈ আছে, চাৰ্জ হৈ থকা নাই"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"চাৰ্জ হ’ল"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"বায়ুৰ গুণগত মান"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"কাষ্টৰ তথ্য"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"গৃহ নিয়ন্ত্ৰণ"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"স্মাৰ্টস্পেচ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"এখন প্ৰ’ফাইল চিত্ৰ বাছনি কৰক"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ডিফ’ল্ট ব্যৱহাৰকাৰীৰ চিহ্ন"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"কায়িক কীব’ৰ্ড"</string>
diff --git a/packages/SettingsLib/res/values-az/arrays.xml b/packages/SettingsLib/res/values-az/arrays.xml
index 48974a7..d1f157a 100644
--- a/packages/SettingsLib/res/values-az/arrays.xml
+++ b/packages/SettingsLib/res/values-az/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Sistem Seçimini istifadə edin (Defolt)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Sistem Seçimini istifadə edin (Defolt)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Sistem Seçimini istifadə edin (Defolt)"</item>
<item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 89b91e6..f6da021 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Eşitmə cihazları"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Eşitmə Aparatlarına qoşuldu"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO audiosuna qoşulub"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE audiosuna qoşulub"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Media audioya birləşdirilib"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefon audiosuna qoşulu"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Fayl transfer serverinə qoşulu"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Manifest dəyərindən asılı olmayaraq çoxpəncərəli rejimdə pəncərə ölçüsünün dəyişdirilməsinə icazə verilsin"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"İxtiyari formada pəncərə yaradılsın"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Eksperimental olaraq ixtiyari formada pəncərə yaradılsın"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Masaüstü rejimi"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Masaüstü rezerv parolu"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Masaüstü tam rezervlər hazırda qorunmayıblar."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Masaüstünün tam rezerv kopyalanması üçün parolu dəyişmək və ya silmək üçün basın"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Tam şarj edilənədək <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - tam şarj edilənədək <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj müvəqqəti məhdudlaşdırılıb"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Naməlum"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Enerji doldurma"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Sürətlə doldurulur"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Asta doldurulur"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Simsiz şarj edilir"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Şarj Doku"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Doldurulmur"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Qoşulub, şarj edilmir"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Şarj edilib"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Havanın keyfiyyəti"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Yayım məlumatı"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Əsas səhifə kontrolları"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profil şəkli seçin"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Defolt istifadəçi ikonası"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziki klaviatura"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 13c3f41..a21a89a 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD zvuk"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Slušni aparati"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Povezano sa slušnim aparatima"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Povezano sa LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano sa LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezano sa zvukom medija"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezano sa zvukom telefona"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Povezano sa serverom za prenos datoteka"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Omogućava promenu veličine svih aktivnosti za režim sa više prozora, bez obzira na vrednosti manifesta."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Omogući prozore proizvoljnog formata"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogućava podršku za eksperimentalne prozore proizvoljnog formata."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Režim za računare"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Lozinka rezervne kopije za računar"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Rezervne kopije čitavog sistema trenutno nisu zaštićene"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dodirnite da biste promenili ili uklonili lozinku za pravljenje rezervnih kopija čitavog sistema na računaru"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do kraja punjenja"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do kraja punjenja"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Punjenje je privremeno ograničeno"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Puni se"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo se puni"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Sporo se puni"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bežično punjenje"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Stanica za punjenje"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Povezano, ne puni se"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Napunjeno"</string>
@@ -601,7 +604,7 @@
<string name="guest_resetting" msgid="7822120170191509566">"Sesija gosta se resetuje…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Želite da resetujete sesiju gosta?"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Time ćete pokrenuti novu sesiju gosta i izbrisati sve aplikacije i podatke iz aktuelne sesije"</string>
- <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Izaći ćete iz režima gosta?"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Izlazite iz režima gosta?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Time ćete izbrisati sve aplikacije i podatke iz aktuelne sesije gosta"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Izađi"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Sačuvaćete aktivnosti gosta?"</string>
@@ -610,7 +613,7 @@
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Sačuvaj"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"Izađi iz režima gosta"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"Resetuj sesiju gosta"</string>
- <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Izađi iz režima gosta"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Zatvori režim gosta"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Sve aktivnosti će biti izbrisane pri izlazu"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Možete da sačuvate ili izbrišete aktivnosti pri izlazu"</string>
<string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Resetujete za brisanje aktivnosti sesije, ili sačuvajte ili izbrišite aktivnosti pri izlazu"</string>
diff --git a/packages/SettingsLib/res/values-be/arrays.xml b/packages/SettingsLib/res/values-be/arrays.xml
index d843629..f16e1c5 100644
--- a/packages/SettingsLib/res/values-be/arrays.xml
+++ b/packages/SettingsLib/res/values-be/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Выбар сістэмы (стандартны)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Аўдыя <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Аўдыя <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Выбар сістэмы (стандартны)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Аўдыя <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Аўдыя <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Выбар сістэмы (стандартны)"</item>
<item msgid="8003118270854840095">"44,1 кГц"</item>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 75d974a..316cefa9 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Аўдыя ў HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Аўдыя ў HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Слыхавыя апараты"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Le audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Падключана да слыхавых апаратаў"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Падключана да LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Падключана да LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Падключана да аўдыё медыа"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Падключана да аўдыё тэлефона"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Падключаны да серверу перадачы файлаў"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Зрабіць усе віды дзейнасці даступнымі для змены памеру ў рэжыме некалькіх вокнаў, незалежна ад значэнняў маніфеста."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Уключыць адвольную форму вокнаў"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Уключыць падтрымку для эксперыментальнай адвольнай формы акна."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Рэжым працоўнага стала"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Пароль для рэз. копіі ПК"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Поўнае рэзервовае капіраванне працоўнага стала зараз не абаронена"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Краніце, каб змяніць або выдаліць пароль для поўнага рэзервовага капіравання працоўнага стала"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Да поўнай зарадкі засталося <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – да поўнай зарадкі засталося: <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Зарадка часова абмежавана"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Невядома"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарадка"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хуткая зарадка"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Павольная зарадка"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бесправадная зарадка"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Зарадная док-станцыя"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не зараджаецца"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Падключана, не зараджаецца"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Зараджаны"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Якасць паветра"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Даныя пра трансляцыю"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Кіраванне домам"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Выберыце відарыс профілю"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Стандартны карыстальніцкі значок"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Фізічная клавіятура"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index c146ef5..f7452df 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Висококачествено аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Висококачествено аудио"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Слухови апарати"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Установена е връзка със слухов апарат"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Свързано с(ъс) LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Свързано с LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Установена е връзка с медийно аудио"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Връзка със звука на телефона"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Установена е връзка със сървър за трансфер на файлове"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Активиране на прозорците в свободна форма"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Активиране на поддръжката за експерименталните прозорци в свободна форма."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Режим за компютри"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Парола за резервни копия"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Понастоящем пълните резервни копия за настолен компютър не са защитени"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Докоснете, за да промените или премахнете паролата за пълни резервни копия на настолния компютър"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Оставащо време до пълно зареждане: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – Оставащо време до пълно зареждане: <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – зареждането временно е ограничено"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарежда се"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Зарежда се бързо"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Зарежда се бавно"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Зарежда се безжично"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Докинг станция за зарежд."</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не се зарежда"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Свързано, не се зарежда"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Заредена"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 1d1472e..0c0c737 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD অডিও: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD অডিও"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"হিয়ারিং এড"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE অডিও"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"হিয়ারিং এডের সাথে কানেক্ট করা হয়েছে"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO-এ কানেক্ট করা হয়েছে"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE অডিও কানেক্ট করা হয়েছে"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"মিডিয়া অডিওতে কানেক্ট রয়েছে"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ফোন অডিওতে কানেক্ট"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ফাইল স্থানান্তর সার্ভারের সঙ্গে কানেক্ট"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলির আকার পরিবর্তনযোগ্য করুন৷"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"ফ্রি-ফর্ম উইন্ডোগুলি সক্ষম করুন"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"পরীক্ষামূলক ফ্রি-ফর্ম উইন্ডোগুলির জন্য সহায়তা সক্ষম করুন৷"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"\'ডেস্কটপ\' মোড"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ডেস্কটপ ব্যাকআপ পাসওয়ার্ড"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ডেস্কটপ পূর্ণ ব্যাকআপ বর্তমানে সুরক্ষিত নয়"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ডেস্কটপের সম্পূর্ণ ব্যাকআপের পাসওয়ার্ডটি পরিবর্তন করতে বা মুছে ফেলতে আলতো চাপুন"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>-এ ব্যাটারি পুরো চার্জ হয়ে যাবে"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>-এ ব্যাটারি পুরো চার্জ হয়ে যাবে"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - চার্জ সাময়িকভাবে বন্ধ করা আছে"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"অজানা"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"চার্জ হচ্ছে"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্রুত চার্জ হচ্ছে"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ধীরে চার্জ হচ্ছে"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"কেবল ছাড়া চার্জ হচ্ছে"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"চার্জিং ডক"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"চার্জ হচ্ছে না"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"কানেক্ট করা থাকলেও চার্জ করা হচ্ছে না"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"চার্জ হয়েছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml
index 262a35f..926ad84 100644
--- a/packages/SettingsLib/res/values-bs/arrays.xml
+++ b/packages/SettingsLib/res/values-bs/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Korištenje odabira sistema (zadano)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Korištenje odabira sistema (zadano)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Korištenje odabira sistema (zadano)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index d85fa56..28c80e9 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Slušni aparati"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE zvuk"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Povezan na slušne aparate"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Povezano sa: LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano s LE zvukom"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezano sa zvukom medija"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezano na zvuk telefona"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Povezano sa serverom za prijenos podataka"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Omogućava mijenjanje veličine svih aktivnosti za prikaz s više prozora, bez obzira na prikazane vrijednosti."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Omogući prozore nepravilnih oblika"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogućava podršku za eksperimentalne prozore nepravilnih oblika."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Način rada radne površine"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Lozinka sigurnosne kopije za računar"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Potpune sigurnosne kopije za računare trenutno nisu zaštićene"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dodirnite da promijenite ili uklonite lozinku za potpune rezervne kopije s radne površine"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do potpune napunjenosti"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do potpune napunjenosti"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Punjenje je privremeno ograničeno"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Sporo punjenje"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bežično punjenje"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Priključna stanica"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Povezano, ne puni se"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Napunjeno"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvalitet zraka"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Podaci o emitiranju"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Kontrole doma"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Odaberite sliku profila"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Zadana ikona korisnika"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fizička tastatura"</string>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index 8c34a1f..b6f1590 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Utilitza la selecció del sistema (predeterminada)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Àudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Àudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Utilitza la selecció del sistema (predeterminada)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Àudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Àudio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Utilitza la selecció del sistema (predeterminada)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 9ddba82..e17adb1 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Àudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Àudio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Audiòfons"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"S\'ha connectat als audiòfons"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Connectat a LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connectat a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connectat a l\'àudio del mitjà"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connectat a àudio del telèfon"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Connectat al servidor de transferència de fitxers"</string>
@@ -408,6 +408,8 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permet ajustar la mida de totes les activitats per al mode multifinestra, independentment dels valors definits"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Activa les finestres de forma lliure"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activa la compatibilitat amb finestres de forma lliure experimentals"</string>
+ <!-- no translation found for desktop_mode (2389067840550544462) -->
+ <skip />
<string name="local_backup_password_title" msgid="4631017948933578709">"Contrasenya per a còpies d\'ordinador"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Les còpies de seguretat completes d\'ordinador no estan protegides"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toca per canviar o suprimir la contrasenya per a les còpies de seguretat completes de l\'ordinador"</string>
@@ -476,13 +478,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> per completar la càrrega"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g>: càrrega limitada temporalment"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconegut"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"S\'està carregant"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregant ràpidament"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carregant lentament"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carregant sense fil"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de càrrega"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"No s\'està carregant"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connectat; no s\'està carregant"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
@@ -661,8 +665,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualitat de l\'aire"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Informació d\'emissió"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Domòtica"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"D\'una ullada"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Tria una foto de perfil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Icona d\'usuari predeterminat"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teclat físic"</string>
diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml
index 90bcaa4..e1d033c 100644
--- a/packages/SettingsLib/res/values-cs/arrays.xml
+++ b/packages/SettingsLib/res/values-cs/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Použít systémový výběr (výchozí)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Zvuk <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Zvuk <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Použít systémový výběr (výchozí)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Zvuk <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Zvuk <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Použít systémový výběr (výchozí)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 7b959f4..eb3a05c 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD zvuk"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Naslouchátka"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Připojeno k naslouchátkům"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Připojeno k LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Připojeno k LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Připojeno ke zvukovému médiu"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Připojeno k náhlavní soupravě"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Připojeno k serveru pro přenos dat"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Umožní změnu velikosti všech aktivit na několik oken (bez ohledu na hodnoty manifestu)"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Aktivovat okna s volným tvarem"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivuje podporu experimentálních oken s volným tvarem"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Režim počítače"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Heslo pro zálohy v počítači"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Úplné zálohy v počítači nejsou v současné době chráněny"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tuto možnost vyberte, chcete-li změnit nebo odebrat heslo pro úplné zálohy do počítače"</string>
@@ -448,7 +449,7 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomálie (červená a zelená)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomálie (modrá a žlutá)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekce barev"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Korekce barev se může hodit, když chcete:<br/> <ol> <li>&nbsp;Zobrazit přesnější barvy.</li> <li>&nbsp;Odstranit barvy kvůli zlepšení soustředění.</li> </ol>"</string>
+ <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Korekce barev se může hodit, když chcete:<br/> <ol> <li>&nbsp;Vidět barvy přesněji.</li> <li>&nbsp;Odstranit barvy kvůli zlepšení soustředění.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do úplného nabití"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabití"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – nabíjení je dočasně omezeno"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznámé"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíjí se"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rychlé nabíjení"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Pomalé nabíjení"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bezdrátové nabíjení"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Nabíjecí dok"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenabíjí se"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Připojeno, nenabíjí se"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Nabito"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvalita vzduchu"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info o odesílání"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Ovládání domácnosti"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Vyberte profilový obrázek"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Výchozí uživatelská ikona"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fyzická klávesnice"</string>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index 155104ae..48a33f6 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Brug systemvalg (standard)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>-lyd"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>-lyd"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Brug systemvalg (standard)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>-lyd"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>-lyd"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Brug systemvalg (standard)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 951d417..84fca3d 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-lyd: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-lyd"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Høreapparater"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Forbundet til høreapparater"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Forbundet med LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Forbundet med LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Forbundet til medielyd"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Forbundet til telefonlyd"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Forbundet til filoverførselsserver"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tillad, at alle aktiviteter kan tilpasses flere vinduer uafhængigt af manifestværdier"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Aktivér vinduer i frit format"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivér understøttelse af eksperimentelle vinduer i frit format"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Computertilstand"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Kode til lokal backup"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Lokale komplette backups er i øjeblikket ikke beskyttet"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tryk for at skifte eller fjerne adgangskoden til fuld lokal backup"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Fuldt opladet om <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – fuldt opladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Opladningen er midlertidigt begrænset"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ukendt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Oplader"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Oplader hurtigt"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Oplader langsomt"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Trådløs opladning"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Dockingstation"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Oplader ikke"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Tilsluttet, oplader ikke"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Opladet"</string>
@@ -610,7 +613,7 @@
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Gem"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"Afslut gæstetilstand"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"Nulstil gæstesession"</string>
- <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Afslut gæstesession"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Afslut gæst"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Al aktivitet slettes ved afslutning"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Du kan gemme eller slette din aktivitet ved afslutning"</string>
<string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Nulstil for at slette sessionsaktiviteten nu, eller gem eller slet aktivitet ved afslutning"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luftkvalitet"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Cast-oplysninger"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Styring af hjem"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Overblik"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Vælg et profilbillede"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikon for standardbruger"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fysisk tastatur"</string>
diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml
index 31126a8..ca999db 100644
--- a/packages/SettingsLib/res/values-de/arrays.xml
+++ b/packages/SettingsLib/res/values-de/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Systemauswahl verwenden (Standard)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>-Audio"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>-Audio"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Systemauswahl verwenden (Standard)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>-Audio"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>-Audio"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Systemauswahl verwenden (Standard)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 3bd4d46..b75e4df 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-Audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-Audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hörhilfen"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Mit Hörhilfen verbunden"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Verbinden mit LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Mit LE Audio verbunden"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Verbunden mit Medien-Audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Verbunden mit Telefon-Audio"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Mit Dateiübertragungsserver verbunden"</string>
@@ -408,6 +408,8 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Die Größe aller Aktivitäten darf, ungeachtet der Manifestwerte, für die Mehrfensterdarstellung angepasst werden"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Freiform-Fenster zulassen"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Unterstützung für experimentelle Freiform-Fenster aktivieren"</string>
+ <!-- no translation found for desktop_mode (2389067840550544462) -->
+ <skip />
<string name="local_backup_password_title" msgid="4631017948933578709">"Passwort für Desktop-Sicherung"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen tippen"</string>
@@ -476,13 +478,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Voll in <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – voll in <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Aufladen vorübergehend eingeschränkt"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unbekannt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Wird aufgeladen"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Schnelles Aufladen"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Langsames Aufladen"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Kabelloses Laden"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Wird am Dock geladen"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Wird nicht geladen"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Verbunden, wird nicht geladen"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Aufgeladen"</string>
@@ -661,8 +665,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Luftqualität"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Streaming-Info"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Smart-Home-Steuerung"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profilbild auswählen"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Standardmäßiges Nutzersymbol"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Physische Tastatur"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 2979e78..cbc2724 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Ήχος HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Ήχος HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Βοηθήματα ακοής"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Έγινε σύνδεση σε βοηθήματα ακοής"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Συνδέθηκε σε LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Συνδέθηκε σε LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Συνδέθηκε σε ήχο πολυμέσων"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Συνδεδεμένο στον ήχο τηλεφώνου"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Συνδεδεμένο σε διακομιστή μεταφοράς αρχείων"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Να έχουν όλες οι δραστηριότητες δυνατότητα αλλαγής μεγέθους για την προβολή πολλαπλών παραθύρων, ανεξάρτητα από τις τιμές του μανιφέστου."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Ενεργοποίηση παραθύρων ελεύθερης μορφής"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ενεργοποίηση υποστήριξης για πειραματικά παράθυρα ελεύθερης μορφής."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Λειτ. επιφάνειας εργασίας"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Εφ/κός κωδικός desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας δεν προστατεύονται αυτήν τη στιγμή"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Πατήστε για αλλαγή ή κατάργηση του κωδικού πρόσβασης για τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Απομένουν <xliff:g id="TIME">%1$s</xliff:g> για πλήρη φόρτιση"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - Απομένουν <xliff:g id="TIME">%2$s</xliff:g> για πλήρη φόρτιση"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Προσωρινός περιορισμός φόρτισης"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Άγνωστο"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Φόρτιση"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ταχεία φόρτιση"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Αργή φόρτιση"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Ασύρματη φόρτιση"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Βάση φόρτισης"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Δεν φορτίζει"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Συνδεδεμένη, δεν φορτίζει"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Φορτισμένη"</string>
@@ -586,9 +589,9 @@
<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="creating_new_user_dialog_message" msgid="7232880257538970375">"Δημιουργία νέου χρήστη…"</string>
- <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Δημιουργία νέου προσκεκλημένου…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Δημιουργία νέου επισκέπτη…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Η δημιουργία νέου χρήστη απέτυχε"</string>
- <string name="add_guest_failed" msgid="8074548434469843443">"Αποτυχία δημιουργίας νέου προσκεκλημένου"</string>
+ <string name="add_guest_failed" msgid="8074548434469843443">"Αποτυχία δημιουργίας νέου επισκέπτη"</string>
<string name="user_nickname" msgid="262624187455825083">"Ψευδώνυμο"</string>
<string name="user_add_user" msgid="7876449291500212468">"Προσθήκη χρήστη"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκέπτη"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 426a6d2..c787941 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hearing Aids"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connected to Hearing Aids"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Connected to LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connected to LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connected to media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connected to phone audio"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Connected to file-transfer server"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizeable for multi-window, regardless of manifest values."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Desktop mode"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging temporarily limited"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charging slowly"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Charging dock"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connected, not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index dc3691b..dc79408 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hearing Aids"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connected to Hearing Aids"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Connected to LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connected to LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connected to media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connected to phone audio"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Connected to file-transfer server"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizeable for multi-window, regardless of manifest values."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Desktop mode"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging temporarily limited"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charging slowly"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Charging dock"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connected, not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 426a6d2..c787941 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hearing Aids"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connected to Hearing Aids"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Connected to LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connected to LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connected to media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connected to phone audio"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Connected to file-transfer server"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizeable for multi-window, regardless of manifest values."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Desktop mode"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging temporarily limited"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charging slowly"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Charging dock"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connected, not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 426a6d2..c787941 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hearing Aids"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connected to Hearing Aids"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Connected to LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connected to LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connected to media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connected to phone audio"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Connected to file-transfer server"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizeable for multi-window, regardless of manifest values."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Desktop mode"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging temporarily limited"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charging slowly"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Charging dock"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connected, not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 8360f01..175ac5d 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hearing Aids"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connected to Hearing Aids"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Connected to LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connected to LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connected to media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connected to phone audio"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Connected to file transfer server"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizable for multi-window, regardless of manifest values."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Desktop mode"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren’t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging temporarily limited"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charging slowly"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Charging Dock"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connected, not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml
index 9b1aa3a..3813808 100644
--- a/packages/SettingsLib/res/values-es-rUS/arrays.xml
+++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Usar selección del sistema (predeterminado)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Usar selección del sistema (predeterminado)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Usar selección del sistema (predeterminado)"</item>
<item msgid="8003118270854840095">"44.1 kHz"</item>
@@ -212,7 +228,7 @@
<item msgid="7051983425968643928">"720 píxeles (seguro)"</item>
<item msgid="7765795608738980305">"1080 píxeles"</item>
<item msgid="8084293856795803592">"1080 píxeles (seguro)"</item>
- <item msgid="938784192903353277">"4 K"</item>
+ <item msgid="938784192903353277">"4K"</item>
<item msgid="8612549335720461635">"4 K (seguro)"</item>
<item msgid="7322156123728520872">"4 K (mejorado)"</item>
<item msgid="7735692090314849188">"4 K (mejorado, seguro)"</item>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index d0f2c64..cf15466 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio en HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio en HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Audífonos"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Audio de bajo consumo"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectado a audífonos"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Conectado a LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado a audio de bajo consumo"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado al audio multimedia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado al audio del dispositivo"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Conectado al servidor de transferencia de archivo"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permitir que todas las actividades puedan cambiar de tamaño para el modo multiventana, sin importar los valores del manifiesto."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Habilitar ventanas de forma libre"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Permitir la compatibilidad con ventanas de forma libre experimentales"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Modo de escritorio"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Contraseñas"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Tus copias de seguridad de escritorio no están protegidas por contraseña."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Presiona para cambiar o quitar la contraseña de las copias de seguridad completas de tu escritorio."</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> para completar"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga limitada temporalmente"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rápidamente"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carga lenta"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carga inalámbrica"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de carga"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"No se está cargando."</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado; no se está cargando"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calidad del aire"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info de reparto"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Control de la casa"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Elige una foto de perfil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ícono de usuario predeterminado"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index 0677864..4924407 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Usar preferencia del sistema (predeterminado)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Usar preferencia del sistema (predeterminado)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Usar preferencia del sistema (predeterminado)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index e75c13c..bb2f59b 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Audífonos"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Le Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectado a audífonos"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Conectado a LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado al audio del medio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado al audio del teléfono"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Conectado con el servidor de transferencia de archivos"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permite que todas las actividades puedan cambiar de tamaño en multiventana independientemente de los valores de manifiesto"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Habilitar ventanas de forma libre"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Permite la compatibilidad con ventanas de forma libre experimentales"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Modo Escritorio"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Contraseña para copias de ordenador"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Las copias de seguridad completas de ordenador no están protegidas"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toca para cambiar o quitar la contraseña de las copias de seguridad completas del escritorio"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> hasta la carga completa"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> hasta la carga completa"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga limitada temporalmente"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carga rápida"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carga lenta"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carga inalámbrica"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de carga"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"No se está cargando"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado pero sin cargar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calidad del aire"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info. de emisión"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Domótica"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"De un vistazo"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Elige una imagen de perfil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Icono de usuario predeterminado"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
diff --git a/packages/SettingsLib/res/values-et/arrays.xml b/packages/SettingsLib/res/values-et/arrays.xml
index d986ecf..0402ac2 100644
--- a/packages/SettingsLib/res/values-et/arrays.xml
+++ b/packages/SettingsLib/res/values-et/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Süsteemi valiku kasutamine (vaikeseade)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Heli: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Heli: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Süsteemi valiku kasutamine (vaikeseade)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Heli: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Heli: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Süsteemi valiku kasutamine (vaikeseade)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 022063c..bcd6ad1 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-heli: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-heli"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Kuuldeaparaadid"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Kuuldeaparaatidega ühendatud"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Ühendatud üksusega LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Ühendatud üksusega LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ühendatud meediumiheliga"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ühendatud telefoniheliga"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Ühendatud failiedastuse serveriga"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Muudetakse kõigi tegevuste suurused mitme aknaga vaates muudetavaks (manifesti väärtustest olenemata)."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Luba vabas vormis aknad"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Lubatakse katseliste vabavormis akende tugi."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Lauaarvuti režiim"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Arvutivarunduse parool"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Täielikud arvutivarundused pole praegu kaitstud"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Puudutage täielike arvutivarunduste parooli muutmiseks või eemaldamiseks"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Täislaadimiseks kulub <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – täislaadimiseks kulub <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimine on ajutiselt piiratud"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tundmatu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laadimine"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiirlaadimine"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Aeglaselt laadimine"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Juhtmevaba laadimine"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Laadimisdokk"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei lae"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ühendatud, ei laeta"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Laetud"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Õhukvaliteet"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Osatäitjate teave"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Kodu juhtimine"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Ülevaade"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Valige profiilipilt"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Vaikekasutajaikoon"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Füüsiline klaviatuur"</string>
diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml
index d166e1b..9c12e95 100644
--- a/packages/SettingsLib/res/values-eu/arrays.xml
+++ b/packages/SettingsLib/res/values-eu/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Erabili sistema-hautapena (lehenetsia)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audioa"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audioa"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Erabili sistema-hautapena (lehenetsia)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audioa"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audioa"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Erabili sistema-hautapena (lehenetsia)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index ba8b1ad..b1ac236 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Kalitate handiko audioa: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Kalitate handiko audioa"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Audifonoak"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Audifonoetara konektatuta"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Konektatu LE_AUDIO-ra"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE audio-ra konektatuta"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Euskarriaren audiora konektatuta"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefonoaren audiora konektatuta"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Fitxategi-transferentziako zerbitzarira konektatuta"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Eman aukera jarduera guztien tamaina doitzeko, hainbat leihotan erabili ahal izan daitezen, ezarritako balioak kontuan izan gabe"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Gaitu estilo libreko leihoak"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Onartu estilo libreko leiho esperimentalak"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Ordenagailuetarako modua"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Babeskopien pasahitz lokala"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Une honetan, ordenagailuko babeskopia osoak ez daude babestuta"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ordenagailuko eduki guztiaren babeskopia egiteko erabiltzen den pasahitza aldatzeko edo kentzeko, sakatu hau"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> guztiz kargatu arte"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kargatzeko aukera mugatuta dago aldi baterako"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ezezaguna"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Kargatzen"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Bizkor kargatzen"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Mantso kargatzen"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Hari gabe kargatzen"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Oinarrian kargatzen"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ez da kargatzen ari"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Konektatuta dago, baina ez da kargatzen ari"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Kargatuta"</string>
@@ -660,10 +663,8 @@
<string name="dream_complication_title_weather" msgid="598609151677172783">"Eguraldia"</string>
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Airearen kalitatea"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Igorpenari buruzko informazioa"</string>
- <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
- <skip />
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Etxeko gailuak kontrolatzeko aukerak"</string>
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Aukeratu profileko argazki bat"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Erabiltzaile lehenetsiaren ikonoa"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teklatu fisikoa"</string>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index b7761dd..41410cb 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"استفاده از انتخاب سیستم (پیشفرض)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"استفاده از انتخاب سیستم (پیشفرض)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"استفاده از انتخاب سیستم (پیشفرض)"</item>
<item msgid="8003118270854840095">"۴۴٫۱ کیلوهرتز"</item>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 911426c..ffd80ec 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"صدای HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"صدای HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"سمعک"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"صدای کممصرف"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"به سمعک متصل شد"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"متصل به LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"به «صدای کممصرف» وصل است"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"به رسانه صوتی متصل شد"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"به تلفن صوتی متصل شد"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"به سرور انتقال فایل متصل شد"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"بدون توجه به مقادیر مانیفست، اندازه همه فعالیتها برای حالت چند پنجرهای میتواند تغییر کند."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"فعال کردن پنجرههای آزاد"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"فعال کردن پشتیبانی برای پنجرههای آزاد آزمایشی."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"حالت رایانه"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"گذرواژه پشتیبانگیری محلی"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"پشتیبانگیری کامل رایانه درحال حاضر محافظت نمیشود"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"برای تغییر یا حذف گذرواژه برای نسخههای پشتیبان کامل رایانهای ضربه بزنید"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> تا شارژ کامل باقی مانده است"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل باقی مانده است"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - شارژ موقتاً محدود شده است"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"ناشناس"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"در حال شارژ شدن"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"درحال شارژ شدن سریع"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"درحال شارژ شدن آهسته"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"درحال شارژ بیسیم"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"پایه شارژ"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"شارژ نمیشود"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"متصل، شارژ نمیشود"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"شارژ کامل شد"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"کیفیت هوا"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"اطلاعات پخش محتوا"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"کنترل لوازم خانگی"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"انتخاب عکس نمایه"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"نماد کاربر پیشفرض"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"صفحهکلید فیزیکی"</string>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index 2969892..842fb8f 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Käytä järjestelmän valintaa (oletus)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ‑ääni"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ‑ääni"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Käytä järjestelmän valintaa (oletus)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ‑ääni"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ‑ääni"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Käytä järjestelmän valintaa (oletus)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 670bcae..3d12c02 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-ääni: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-ääni"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Kuulolaitteet"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Yhdistetty kuulolaitteisiin"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO yhdistetty"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio yhdistetty"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Yhdistetty median ääneen"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Yhdistetty puhelimen ääneen"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Yhdistetty tiedostonsiirtopalvelimeen"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Pakota kaikki toiminnot hyväksymään koon muuttaminen usean ikkunan tilassa luettelon arvoista riippumatta"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Ota käyttöön vapaamuotoiset ikkunat"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ota kokeellisten vapaamuotoisten ikkunoiden tuki käyttöön"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Työpöytätila"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Varmuuskop. salasana"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Tietokoneen kaikkien tietojen varmuuskopiointia ei ole tällä hetkellä suojattu"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Vaihda tai poista tietokoneen kaikkien tietojen varmuuskopioinnin salasana koskettamalla."</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> kunnes täynnä"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kunnes täynnä"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Lataamista rajoitettu väliaikaisesti"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tuntematon"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Ladataan"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Nopea lataus"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Hidas lataus"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Langaton lataus"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Latausteline"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei laturissa"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Yhdistetty, ei ladata"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Ladattu"</string>
@@ -575,7 +578,7 @@
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Lisätäänkö käyttäjä nyt?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Varmista, että käyttäjä voi ottaa laitteen nyt ja määrittää oman tilansa."</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Määritetäänkö profiilin asetukset nyt?"</string>
- <string name="user_setup_button_setup_now" msgid="1708269547187760639">"Määritä nyt"</string>
+ <string name="user_setup_button_setup_now" msgid="1708269547187760639">"Ota käyttöön nyt"</string>
<string name="user_setup_button_setup_later" msgid="8712980133555493516">"Ei nyt"</string>
<string name="user_add_user_type_title" msgid="551279664052914497">"Lisää"</string>
<string name="user_new_user_name" msgid="60979820612818840">"Uusi käyttäjä"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ilmanlaatu"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Striimaustiedot"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Kodin ohjaus"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Pikanäkymä"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Valitse profiilikuva"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Oletuskäyttäjäkuvake"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fyysinen näppäimistö"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 5d6aaeb..7dfc86e 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD : <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Prothèses auditives"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connecté aux prothèses auditives"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Connecté à LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connecté par LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connecté aux paramètres audio du média"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connecté à l\'audio du téléphone"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Connexion au serveur de transfert de fichiers"</string>
@@ -408,6 +408,8 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permet de redimensionner toutes les activités pour le mode multi-fenêtre, indépendamment des valeurs du fichier manifeste."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Activer les fenêtres de forme libre"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activer la compatibilité avec les fenêtres de forme libre expérimentales."</string>
+ <!-- no translation found for desktop_mode (2389067840550544462) -->
+ <skip />
<string name="local_backup_password_title" msgid="4631017948933578709">"Mot de passe sauvegarde PC"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Touchez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur ordinateur."</string>
@@ -476,13 +478,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> jusqu\'à la recharge complète"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la recharge complète)"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> : recharge temporairement limitée"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charge en cours…"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Recharge rapide"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Recharge lente"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"En recharge sans fil"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Station de recharge"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"N\'est pas en charge"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connecté, pas en charge"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Chargée"</string>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
index 80ac7e4..92546da 100644
--- a/packages/SettingsLib/res/values-fr/arrays.xml
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Utiliser la sélection du système (par défaut)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Utiliser la sélection du système (par défaut)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Utiliser la sélection du système (par défaut)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index dad8668..52d15f1 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD : <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Appareils auditifs"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connexion établie avec les appareils auditifs"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Connecté à LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connecté à LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Connecté aux paramètres audio du média"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Connecté aux paramètres audio du téléphone"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Connexion au serveur de transfert de fichiers"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Rendre toutes les activités redimensionnables pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Activer les fenêtres de forme libre"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activer la compatibilité avec les fenêtres de forme libre expérimentales"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Mode ordinateur"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Mot de passe de sauvegarde ordi"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Les sauvegardes complètes sur ordi ne sont actuellement pas protégées"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Appuyez pour modifier ou supprimer le mot de passe des sauvegardes complètes sur ordi."</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Chargée à 100 %% dans <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Recharge momentanément limitée"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Batterie en charge"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charge rapide"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charge lente"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"En charge sans fil"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Station de charge"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Pas en charge"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connectée, pas en charge"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Chargée"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Qualité de l\'air"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Infos distribution"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Domotique"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Choisissez une photo de profil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Icône de l\'utilisateur par défaut"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Clavier physique"</string>
diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml
index b6cf48e..f663120 100644
--- a/packages/SettingsLib/res/values-gl/arrays.xml
+++ b/packages/SettingsLib/res/values-gl/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Usar selección do sistema (predeterminado)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Usa a selección do sistema (predeterminado)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Usar selección do sistema (predeterminado)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 3fd7f43..ef73b59 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio en HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio en HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Audiófonos"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Audio de baixo consumo"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectado a audiófonos"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Conexión establecida con LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Estableceuse conexión co audio de baixo consumo"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado ao audio multimedia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado ao audio do teléfono"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Conectado ao servidor de transferencia de ficheiros"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permite axustar o tamaño de todas as actividades para o modo multiventá, independentemente dos valores do manifesto"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Activar ventás de forma libre"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activa a compatibilidade con ventás de forma libre experimentais"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Modo de escritorio"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Contrasinal para copias"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"As copias de seguranza de ordenador completas non están protexidas"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toca para cambiar ou quitar o contrasinal para as copias de seguranza completas de ordenador"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> para completar a carga"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> para completar a carga)"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga limitada temporalmente"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Descoñecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rapidamente"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Cargando lentamente"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Cargando sen fíos"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de carga"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Non se está cargando"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado, sen cargar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
@@ -660,10 +663,8 @@
<string name="dream_complication_title_weather" msgid="598609151677172783">"O tempo"</string>
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Calidade do aire"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Datos da emisión"</string>
- <!-- no translation found for dream_complication_title_home_controls (9153381632476738811) -->
- <skip />
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Controis domóticos"</string>
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Espazo intelixente"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Escolle unha imaxe do perfil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Icona do usuario predeterminado"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Teclado físico"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index eb84599..02c9927 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ઑડિયો: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ઑડિયો"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"શ્રવણ યંત્રો"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE ઑડિયો"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"શ્રવણ યંત્રો સાથે કનેક્ટ કરેલું છે"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO સાથે કનેક્ટેડ છે"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ઑડિયોથી કનેક્ટેડ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"મીડિયા ઑડિઓ સાથે કનેક્ટ કર્યુ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ફોન ઑડિઓ સાથે કનેક્ટ થયાં"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ફાઇલ સ્થાનાંતરણ સેવાથી કનેક્ટ થયાં"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"મૅનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, તમામ પ્રવૃત્તિઓને મલ્ટી-વિન્ડો માટે ફરીથી કદ બદલી શકે તેવી બનાવો."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"ફ્રીફોર્મ વિન્ડો ચાલુ કરો"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"પ્રાયોગિક ફ્રીફોર્મ વિન્ડો માટે સપોર્ટને ચાલુ કરો."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"ડેસ્કટૉપ મોડ"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ડેસ્કટૉપ બૅકઅપ પાસવર્ડ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ડેસ્કટૉપ સંપૂર્ણ બૅકઅપ હાલમાં સુરક્ષિત નથી"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ્સ માટેનો પાસવર્ડ બદલવા અથવા દૂર કરવા માટે ટૅચ કરો"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"પૂર્ણ ચાર્જ થવામાં <xliff:g id="TIME">%1$s</xliff:g> બાકી છે"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - પૂર્ણ ચાર્જ થવામાં <xliff:g id="TIME">%2$s</xliff:g> બાકી છે"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જ કરવાનું થોડા સમય માટે મર્યાદિત કરવામાં આવ્યું છે"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"અજાણ્યું"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ચાર્જ થઈ રહ્યું છે"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ઝડપથી ચાર્જ થાય છે"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ધીમેથી ચાર્જ થાય છે"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"વાયરલેસથી ચાર્જિંગ"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ડૉકથી ચાર્જ થઈ રહ્યું છે"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ચાર્જ થઈ રહ્યું નથી"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"કનેક્ટ કરેલું છે, પણ ચાર્જ થઈ રહ્યું નથી"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ચાર્જ થયું"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index e529756..6dbb2b4 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"एचडी ऑडियो: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"एचडी ऑडियो"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"कान की मशीन"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"सुनने में मदद करने वाले डिवाइस से कनेक्ट है"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO से कनेक्ट किया गया"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio से कनेक्ट किया गया"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"मीडिया ऑडियो से कनेक्ट किया गया"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"फ़ोन ऑडियो से कनेक्ट किया गया"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"फ़ाइल स्थानांतरण सर्वर से कनेक्ट किया गया"</string>
@@ -408,6 +408,8 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"सभी गतिविधियों को मल्टी-विंडो (एक से ज़्यादा ऐप्लिकेशन, एक साथ) के लिए साइज़ बदलने लायक बनाएं, चाहे उनकी मेनिफ़ेस्ट वैल्यू कुछ भी हो."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"फ़्रीफ़ॉर्म विंडो (एक साथ कई विंडो दिखाना) चालू करें"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"जांच के लिए बनी फ़्रीफ़ॉर्म विंडो के लिए सहायता चालू करें."</string>
+ <!-- no translation found for desktop_mode (2389067840550544462) -->
+ <skip />
<string name="local_backup_password_title" msgid="4631017948933578709">"डेस्कटॉप बैक अप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"डेस्कटॉप के पूरे बैक अप फ़िलहाल सुरक्षित नहीं हैं"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"डेस्कटॉप के पूरे बैक अप का पासवर्ड बदलने या हटाने के लिए टैप करें"</string>
@@ -476,13 +478,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> में बैटरी पूरी चार्ज हो जाएगी"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> में बैटरी पूरी चार्ज हो जाएगी"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंग कुछ समय के लिए रोकी गई"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हो रही है"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"तेज़ चार्ज हो रही है"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"धीरे चार्ज हो रही है"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेस चार्जिंग"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"चार्जिंग डॉक"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज नहीं हो रही है"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"कनेक्ट किया गया, चार्ज नहीं हो रहा है"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"बैटरी चार्ज हो गई"</string>
@@ -602,7 +606,7 @@
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"क्या मेहमान मोड के मौजूदा सेशन को रीसेट करना है?"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ऐसा करने पर, मेहमान के तौर पर ब्राउज़ करने का एक नया सेशन शुरू हो जाएगा. साथ ही, पिछले सेशन में मौजूद डेटा और इस्तेमाल किए जा रहे ऐप्लिकेशन को मिटा दिया जाएगा"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"मेहमान मोड से बाहर निकलना है?"</string>
- <string name="guest_exit_dialog_message" msgid="1743218864242719783">"इससे, मेहमान मोड के मौजूदा सेशन का डेटा और इसमें इस्तेमाल हो रहे ऐप मिट जाएंगे"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"इससे, मेहमान मोड के मौजूदा सेशन का डेटा और इसमें इस्तेमाल हो रहे ऐप्लिकेशन मिट जाएंगे"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"बाहर निकलें"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"मेहमान मोड की गतिविधि को सेव करना है?"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"मौजूदा सेशन की गतिविधि को सेव किया जा सकता है या सभी ऐप और डेटा को मिटाया जा सकता है"</string>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
index 0e66858..559383a 100644
--- a/packages/SettingsLib/res/values-hr/arrays.xml
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Upotreba odabira sustava (zadano)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Upotreba odabira sustava (zadano)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Upotreba odabira sustava (zadano)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 598f65f..e3f8ba8b 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Slušni aparati"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE_AUDIO"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Povezano sa Slušnim aparatima"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Povezano s profilom LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano s profilom LE_AUDIO"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezano s medijskim zvukom"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezano sa telefonskim zvukom"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Povezano s poslužiteljem za prijenos datoteka"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Omogući mijenjanje veličine svih aktivnosti za više prozora, neovisno o vrijednostima manifesta."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Omogući prozore slobodnog oblika"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogući podršku za eksperimentalne prozore slobodnog oblika."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Stolni način rada"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Zaporka sigurnosne kopije"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Potpune sigurnosne kopije na stolnom računalu trenutačno nisu zaštićene"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dodirnite da biste promijenili ili uklonili zaporku za potpune sigurnosne kopije na računalu"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do napunjenosti"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napunjenosti"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je privremeno ograničeno"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Sporo punjenje"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bežično punjenje"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Stanica za punjenje"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Povezano, ne puni se"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Napunjeno"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kvaliteta zraka"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Inform. o emitiranju"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Upravlj. kuć. uređ."</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Odabir profilne slike"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikona zadanog korisnika"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fizička tipkovnica"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 8eae4d0..8ff6031 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hallókészülékek"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Alacsony energiaszintű hangátvitel"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Hallókészülékhez csatlakoztatva"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Csatlakoztatva ehhez: LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Csatlakoztatva az alacsony energiaszintű hangátvitelhez"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Csatlakoztatva az eszköz hangjához"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Csatlakoztatva a telefon hangjához"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Csatlakozva a fájlküldő szerverhez"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Legyen az összes tevékenység átméretezhető a többablakos megjelenítés érdekében a jegyzékértékektől függetlenül."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Szabad formájú ablakok engedélyezése"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Kísérleti, szabad formájú ablakok támogatásának engedélyezése."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Asztali üzemmód"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Asztali mentés jelszava"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Az asztali teljes biztonsági mentések jelenleg nem védettek."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Koppintson ide az asztali teljes mentések jelszavának módosításához vagy eltávolításához"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> a teljes töltöttségig"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a teljes töltöttségig"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Töltés ideiglenesen korlátozva"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ismeretlen"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Töltés"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Gyorstöltés"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Lassú töltés"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Vezeték nélküli töltés"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Töltődokk"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nem tölt"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Csatlakoztatva, nem töltődik"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Feltöltve"</string>
diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml
index 50d7c7f..009875d 100644
--- a/packages/SettingsLib/res/values-hy/arrays.xml
+++ b/packages/SettingsLib/res/values-hy/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> աուդիո"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> աուդիո"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> աուդիո"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> աուդիո"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
<item msgid="8003118270854840095">"44,1 կՀց"</item>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 2a5fbfb..8a458668 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD աուդիո՝ <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD աուդիո"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Լսողական ապարատ"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Լսողական ապարատը միացված է"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Միացած է LE_AUDIO-ին"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Միացած է LE audio-ին"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Միացված է մեդիա աուդիոյին"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Միացված է հեռախոսի ձայնային տվյալներին"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Միացված է ֆայլերի փոխանցման սերվերին"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Ակտիվացնել կամայական ձևի պատուհանները"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Միացնել ազատ ձևի փորձնական պատուհանների աջակցումը:"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Համակարգչի ռեժիմ"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Աշխատասեղանի պահուստավորման գաղտնաբառ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Աշխատասեղանի ամբողջական պահուստավորումները այժմ պաշտպանված չեն"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Հպեք՝ աշխատասեղանի ամբողջական պահուստավորման գաղտնաբառը փոխելու կամ հեռացնելու համար"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորումը ժամանակավորապես սահմանափակված է"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Անհայտ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Լիցքավորում"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Արագ լիցքավորում"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Դանդաղ լիցքավորում"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Անլար լիցքավորում"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Լիցքավորում դոկ-կայանի միջոցով"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Չի լիցքավորվում"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Միացված է, չի լիցքավորվում"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Լիցքավորված է"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Օդի որակը"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Հեռարձակման տվյալներ"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Տան կարգավորումներ"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Պրոֆիլի նկար ընտրեք"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Օգտատիրոջ կանխադրված պատկերակ"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Ֆիզիկական ստեղնաշար"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 5b0ad98..9527417 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Gunakan Pilihan Sistem (Default)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Gunakan Pilihan Sistem (Default)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Gunakan Pilihan Sistem (Default)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 08ec2b1..6dc5697 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Alat Bantu Dengar"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Terhubung ke Alat Bantu Dengar"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Terhubung ke LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Terhubung ke LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Terhubung ke media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Terhubung ke audio ponsel"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Sambungkan ke server transfer file"</string>
@@ -232,7 +232,7 @@
<string name="vpn_settings_not_available" msgid="2894137119965668920">"Setelan VPN tidak tersedia untuk pengguna ini"</string>
<string name="tethering_settings_not_available" msgid="266821736434699780">"Setelan Penambatan tidak tersedia untuk pengguna ini"</string>
<string name="apn_settings_not_available" msgid="1147111671403342300">"Setelan Nama Titik Akses tidak tersedia untuk pengguna ini"</string>
- <string name="enable_adb" msgid="8072776357237289039">"Debugging USB"</string>
+ <string name="enable_adb" msgid="8072776357237289039">"Proses debug USB"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"Mode debug ketika USB terhubung"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"Cabut otorisasi debug USB"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"Proses debug nirkabel"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Membuat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Aktifkan jendela berformat bebas"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Mengaktifkan dukungan untuk jendela eksperimental berformat bebas."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Mode desktop"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Sandi cadangan desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Saat ini cadangan desktop penuh tidak dilindungi"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ketuk guna mengubah atau menghapus sandi untuk cadangan lengkap desktop"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> lagi sampai penuh"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi sampai penuh"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengisian daya dibatasi sementara"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Mengisi daya"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengisi daya cepat"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Mengisi daya lambat"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Mengisi daya nirkabel"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Mengisi Daya di Dok"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Tidak mengisi daya"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Terhubung, tidak mengisi daya"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Terisi"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kualitas Udara"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Info Transmisi"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Kontrol Rumah"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Pilih foto profil"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikon pengguna default"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Keyboard fisik"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index dc2036f..4531fb1 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -117,7 +117,7 @@
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Skráaflutningur"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"Inntakstæki"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"Internetaðgangur"</string>
- <string name="bluetooth_profile_pbap" msgid="4262303387989406171">"Tengiliðir, SMS-skilaboð og símtalaferill"</string>
+ <string name="bluetooth_profile_pbap" msgid="4262303387989406171">"Deiling tengiliða og símtalaferils"</string>
<string name="bluetooth_profile_pbap_summary" msgid="6466456791354759132">"Nota til að deila tengiliðum og símtalaferli"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Deiling nettengingar"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"Textaskilaboð"</string>
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-hljóð: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-hljóð"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Heyrnartæki"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE-hljóð"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Tengt við heyrnartæki"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Tengt við LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Tengt við LE-hljóð"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Tengt við hljóðspilun efnis"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Tengt við hljóð símans"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Tengt við skráaflutningsþjón"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gera stærð allrar virkni breytanlega svo að hún henti fyrir marga glugga, óháð gildum í upplýsingaskrá."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Virkja glugga með frjálsu sniði"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Virkja stuðning við glugga með frjálsu sniði á tilraunastigi."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Skjáborðsstilling"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Aðgangsorð tölvuafritunar"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Heildarafritun á tölvu er ekki varin sem stendur."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ýttu til að breyta eða fjarlægja aðgangsorðið fyrir heildarafritun á tölvu"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> fram að fullri hleðslu"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> fram að fullri hleðslu"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Hleðsla takmörkuð tímabundið"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Óþekkt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Í hleðslu"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hröð hleðsla"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Hæg hleðsla"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Hleður þráðlaust"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Hleður í dokku"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ekki í hleðslu"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Tengt, ekki í hleðslu"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Fullhlaðin"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 201fb48..87f5870 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -117,7 +117,7 @@
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Trasferimento file"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"Dispositivo di input"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"Accesso a Internet"</string>
- <string name="bluetooth_profile_pbap" msgid="4262303387989406171">"Condivis. contatti e cronologia chiamate"</string>
+ <string name="bluetooth_profile_pbap" msgid="4262303387989406171">"Condivisione contatti e cronologia chiamate"</string>
<string name="bluetooth_profile_pbap_summary" msgid="6466456791354759132">"Usa per condivisione di contatti e cronologia chiamate"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Condivisione connessione Internet"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"SMS"</string>
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Apparecchi acustici"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Connessione con gli apparecchi acustici stabilita"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Connesso a LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Connesso a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Collegato ad audio media"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Collegato ad audio telefono"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Collegato al server di trasferimento file"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Rendi il formato di tutte le attività modificabile per la modalità multi-finestra, indipendentemente dai valori manifest"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Attiva finestre a forma libera"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Attiva il supporto delle finestre a forma libera sperimentali"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Modalità desktop"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Password di backup desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"I backup desktop completi non sono attualmente protetti"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tocca per modificare o rimuovere la password per i backup desktop completi"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> alla ricarica completa"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> alla ricarica completa"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ricarica momentaneamente limitata"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Sconosciuta"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"In carica"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ricarica veloce"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Ricarica lenta"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"In carica, wireless"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"In carica nel dock"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Non in carica"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Dispositivo connesso, non in carica"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carica"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index e6f1bcb..5f567c6 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"אודיו באיכות HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"אודיו באיכות HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"מכשירי שמיעה"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"מחובר אל מכשירי שמיעה"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"מחובר אל LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"מחובר אל LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"מחובר לאודיו של מדיה"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"מחובר לאודיו של הטלפון"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"מחובר לשרת העברת קבצים"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"מאפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא קשר לערך המניפסט."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"הפעלת האפשרות לשנות את הגודל והמיקום של החלונות"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"הפעלת תמיכה בתכונה הניסיונית של שינוי הגודל והמיקום של החלונות."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"ממשק המחשב"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"סיסמת גיבוי שולחן העבודה"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"גיבויים מלאים בשולחן העבודה אינם מוגנים כעת"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"יש להקיש כדי לשנות או להסיר את הסיסמה לגיבויים מלאים בשולחן העבודה"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"הזמן הנותר לטעינה מלאה: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – הזמן הנותר לטעינה מלאה: <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – הטעינה מוגבלת זמנית"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"לא ידוע"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"בטעינה"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"הסוללה נטענת מהר"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"הסוללה נטענת לאט"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"בטעינה אלחוטית"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"אביזר עגינה לטעינה"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"לא בטעינה"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"מחובר, לא בטעינה"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"הסוללה טעונה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index c42679b..49dfb92 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD オーディオ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD オーディオ"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"補聴器"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"補聴器に接続"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO に接続"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio に接続"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"メディアの音声に接続"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"携帯電話の音声に接続"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ファイル転送サーバーに接続"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようにします。"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"フリーフォーム ウィンドウを有効にする"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"試験運用機能のフリーフォーム ウィンドウのサポートを有効にします。"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"デスクトップ モード"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"PC バックアップ パスワード"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"デスクトップのフルバックアップは現在保護されていません"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"デスクトップのフルバックアップ用のパスワードを変更または削除する場合にタップします"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"完了まであと <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - 完了まであと <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電は一時的に制限されています"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"急速充電中"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"低速充電中"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ワイヤレス充電中"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"充電ホルダー"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"充電していません"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"接続済み、充電していません"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"充電が完了しました"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index cd206e6..93dfb44 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD აუდიო: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD აუდიო"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"სმენის მოწყობილობები"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE აუდიო"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"დაკავშირებულია სმენის მოწყობილობებთან"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"დაკავშირებულია შემდეგთან: LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"დაკავშირებულია LE აუდიოსთან"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"დაკავშირებულია აუდიო მულტიმედიურ სისტემასთან"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"დაკავშირებულია ტელეფონის აუდიო მოწყობილობასთან"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"დაკავშირებულია ფაილების გადაცემის სერვერთან"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"მანიფესტის მნიშვნელობების მიუხედავად, მრავალი ფანჯრის რეჟიმისთვის ყველა აქტივობის ზომაცვლადად გადაქცევა."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"თავისუფალი ფორმის მქონე ფანჯრების ჩართვა"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"თავისუფალი ფორმის მქონე ფანჯრების მხარდაჭერის ექსპერიმენტული ფუნქციის ჩართვა."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"დესკტოპის რეჟიმი"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"დესკტოპის სარეზერვო ასლის პაროლი"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"დესკტოპის სრული სარეზერვო ასლები ამჟამად დაცული არ არის"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"შეეხეთ დესკტოპის სრული სარეზერვო ასლების პაროლის შესაცვლელად ან წასაშლელად"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"სრულ დატენვამდე დარჩენილია <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> — სრულ დატენვამდე დარჩენილია <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> — დატენვა დროებით შეზღუდულია"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"უცნობი"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"იტენება"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"სწრაფად იტენება"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ნელა იტენება"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"უსადენოდ დატენა"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"დამტენი სამაგრი"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"არ იტენება"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"დაკავშირებულია, არ იტენება"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"დატენილია"</string>
diff --git a/packages/SettingsLib/res/values-kk/arrays.xml b/packages/SettingsLib/res/values-kk/arrays.xml
index fc998e7..9971f86 100644
--- a/packages/SettingsLib/res/values-kk/arrays.xml
+++ b/packages/SettingsLib/res/values-kk/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Жүйенің таңдағанын алу (әдепкі)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> аудиокодегі"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> аудиокодегі"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"L34C"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Жүйенің таңдағанын алу (әдепкі)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> аудиокодегі"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> аудиокодегі"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"L34C"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Жүйенің таңдағанын алу (әдепкі)"</item>
<item msgid="8003118270854840095">"44,1 кГц"</item>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index d0b8c0d..4733c28 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD форматты аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD форматты аудио"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Есту аппараттары"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Есту аппараттарына жалғанған"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO құрылғысына жалғанды."</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio-ға жалғанды."</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Медиа аудиосына жалғанған"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Телефон аудиосына қосылған"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Файл жіберу серверіне жалғанған"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Манифест мәндеріне қарамастан, бірнеше терезе режимінде барлық әрекеттердің өлшемін өзгертуге рұқсат беру"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Еркін пішінді терезелерге рұқсат беру"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Еркін пішінді терезелерді құру эксперименттік функиясын қосу"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Компьютер режимі"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Компьютердегі сақтық көшірме құпия сөзі"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Компьютердегі толық сақтық көшірмелер қазір қорғалмаған."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Үстелдік компьютердің толық сақтық көшірмелерінің кілтсөзін өзгерту немесе жою үшін түртіңіз"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Толық зарядталғанға дейін <xliff:g id="TIME">%1$s</xliff:g> қалды."</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – толық зарядталғанға дейін <xliff:g id="TIME">%2$s</xliff:g> қалды."</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Зарядтау уақытша шектелген"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Белгісіз"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарядталуда"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Жылдам зарядталуда"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Баяу зарядталуда"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Сымсыз зарядталуда"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Қондыру станциясы зарядталуда"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Зарядталу орындалып жатқан жоқ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Жалғанған, зарядталып жатқан жоқ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Зарядталды"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ауа сапасы"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Трансляция ақпараты"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Үйді басқару элементтері"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Профиль суретін таңдау"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Әдепкі пайдаланушы белгішесі"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Пернетақта"</string>
diff --git a/packages/SettingsLib/res/values-km/arrays.xml b/packages/SettingsLib/res/values-km/arrays.xml
index a005f4d..2269df1 100644
--- a/packages/SettingsLib/res/values-km/arrays.xml
+++ b/packages/SettingsLib/res/values-km/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"ប្រើការជ្រើសរើសប្រព័ន្ធ (លំនាំដើម)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g>សំឡេង <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g>សំឡេង <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"ប្រើការជ្រើសរើសប្រព័ន្ធ (លំនាំដើម)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g>សំឡេង <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g>សំឡេង <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"ប្រើការជ្រើសរើសប្រព័ន្ធ (លំនាំដើម)"</item>
<item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index fa759a6..7715985 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"សំឡេងកម្រិត HD៖ <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"សំឡេងកម្រិត HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"បានភ្ជាប់ទៅឧបករណ៍ជំនួយការស្ដាប់"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"បានភ្ជាប់ទៅ LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"បានភ្ជាប់ទៅ LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"បានភ្ជាប់ទៅអូឌីយ៉ូមេឌៀ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"តភ្ជាប់ទៅអូឌីយ៉ូទូរស័ព្ទ"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"បានតភ្ជាប់ទៅម៉ាស៊ីនមេផ្ទេរឯកសារ"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ធ្វើឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេសថ៍។"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"បើកដំណើរការផ្ទាំងវិនដូទម្រង់សេរី"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"បើកឱ្យអាចប្រើផ្ទាំងវិនដូទម្រង់សេរីពិសោធន៍។"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"មុខងារកុំព្យូទ័រ"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ពាក្យសម្ងាត់បម្រុងទុកលើកុំព្យូទ័រ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"បច្ចុប្បន្ន ការបម្រុងទុកពេញលេញនៅលើកុំព្យូទ័រមិនត្រូវបានការពារទេ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ប៉ះដើម្បីប្ដូរ ឬយកពាក្យសម្ងាត់ចេញសម្រាប់ការបម្រុងទុកពេញលេញលើកុំព្យូទ័រ"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> ទៀតទើបពេញ"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - នៅសល់ <xliff:g id="TIME">%2$s</xliff:g> ទៀតទើបពេញ"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - បានដាក់កំហិតលើការសាកថ្មជាបណ្ដោះអាសន្ន"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"មិនស្គាល់"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"កំពុងសាកថ្ម"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"កំពុងសាកថ្មយ៉ាងឆាប់រហ័ស"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"កំពុងសាកថ្មយឺត"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"កំពុងសាកថ្មឥតខ្សែ"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ឧបករណ៍ភ្ជាប់សាកថ្ម"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"មិនកំពុងសាកថ្ម"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"បានភ្ជាប់ មិនកំពុងសាកថ្ម"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"បានសាកថ្មពេញ"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"គុណភាពខ្យល់"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ព័ត៌មានអំពីការបញ្ជូន"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ការគ្រប់គ្រងផ្ទះ"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ជ្រើសរើសរូបភាពកម្រងព័ត៌មាន"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"រូបអ្នកប្រើប្រាស់លំនាំដើម"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"ក្ដារចុចរូបវន្ត"</string>
diff --git a/packages/SettingsLib/res/values-kn/arrays.xml b/packages/SettingsLib/res/values-kn/arrays.xml
index b6014ce..975f60f 100644
--- a/packages/SettingsLib/res/values-kn/arrays.xml
+++ b/packages/SettingsLib/res/values-kn/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ಆಡಿಯೋ"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ಆಡಿಯೋ"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ಆಡಿಯೋ"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ಆಡಿಯೋ"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"ಸಿಸ್ಟಂ ಆಯ್ಕೆಯನ್ನು ಬಳಸಿ (ಡಿಫಾಲ್ಟ್)"</item>
<item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 5b0d684..66e2da8 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ಆಡಿಯೋ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ಆಡಿಯೋ"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE ಆಡಿಯೋ"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ಶ್ರವಣ ಸಾಧನಗಳಿಗೆ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO ಗೆ ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ಆಡಿಯೋಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ಮಾಧ್ಯಮ ಆಡಿಯೋಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ಫೋನ್ ಆಡಿಯೋಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ಫೈಲ್ ವರ್ಗಾವಣೆ ಸರ್ವರ್ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡಿ."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"ಪ್ರಾಯೋಗಿಕ ಫ್ರೀಫಾರ್ಮ್ ವಿಂಡೊಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"ಡೆಸ್ಕ್ಟಾಪ್ ಮೋಡ್"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ಡೆಸ್ಕ್ಟಾಪ್ ಬ್ಯಾಕಪ್ ಪಾಸ್ವರ್ಡ್"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ಡೆಸ್ಕ್ಟಾಪ್ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್ಗಳನ್ನು ಪ್ರಸ್ತುತ ರಕ್ಷಿಸಲಾಗಿಲ್ಲ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ಡೆಸ್ಕ್ಟಾಪ್ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್ಗಳಿಗೆ ಪಾಸ್ವರ್ಡ್ ಬದಲಾಯಿಸಲು ಅಥವಾ ತೆಗೆದುಹಾಕಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> - ಸಮಯದಲ್ಲಿ ಪೂರ್ತಿ ಚಾರ್ಜ್ ಆಗುತ್ತದೆ"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ಸಮಯದಲ್ಲಿ ಪೂರ್ತಿ ಚಾರ್ಜ್ ಆಗುತ್ತದೆ"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ಸೀಮಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"ಅಪರಿಚಿತ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ವೇಗದ ಚಾರ್ಜಿಂಗ್"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ನಿಧಾನ ಗತಿಯ ಚಾರ್ಜಿಂಗ್"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ವೈರ್ಲೆಸ್ ಚಾರ್ಜಿಂಗ್"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ಚಾರ್ಜಿಂಗ್ ಡಾಕ್"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ಚಾರ್ಜ್ ಆಗುತ್ತಿಲ್ಲ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ಕನೆಕ್ಟ್ ಆಗಿದೆ, ಚಾರ್ಜ್ ಆಗುತ್ತಿಲ್ಲ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"ವಾಯು ಗುಣಮಟ್ಟ"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ಬಿತ್ತರಿಸಿದ ಮಾಹಿತಿ"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ಹೋಮ್ ನಿಯಂತ್ರಣಗಳು"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ಪ್ರೊಫೈಲ್ ಚಿತ್ರವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ಡೀಫಾಲ್ಟ್ ಬಳಕೆದಾರರ ಐಕಾನ್"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್"</string>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
index 7138113..16b840b 100644
--- a/packages/SettingsLib/res/values-ko/arrays.xml
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"시스템 설정 사용(기본)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> 오디오"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> 오디오"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"시스템 설정 사용(기본)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> 오디오"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> 오디오"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"시스템 설정 사용(기본)"</item>
<item msgid="8003118270854840095">"44.1kHz"</item>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index ae9c19f..111dd34 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD 오디오: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD 오디오"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"보청기"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE 오디오"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"보청기에 연결됨"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO에 연결됨"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE 오디오에 연결됨"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"미디어 오디오에 연결됨"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"휴대전화 오디오에 연결됨"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"파일 전송 서버에 연결됨"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"자유 형식 창 사용"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"자유 형식 창 지원 사용"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"데스크톱 모드"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"데스크톱 백업 비밀번호"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"데스크톱 전체 백업에 비밀번호가 설정되어 있지 않음"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"데스크톱 전체 백업에 대한 비밀번호를 변경하거나 삭제하려면 탭하세요."</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> 후 충전 완료"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> 후 충전 완료"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전이 일시적으로 제한됨"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"알 수 없음"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"충전 중"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"고속 충전 중"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"저속 충전 중"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"무선 충전 중"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"충전 도크"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"충전 안함"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"연결됨, 충전 중 아님"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"충전됨"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"대기 상태"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"전송 정보"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"홈 컨트롤"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"프로필 사진 선택하기"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"기본 사용자 아이콘"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"물리적 키보드"</string>
diff --git a/packages/SettingsLib/res/values-ky/arrays.xml b/packages/SettingsLib/res/values-ky/arrays.xml
index 40271f7..700aae1 100644
--- a/packages/SettingsLib/res/values-ky/arrays.xml
+++ b/packages/SettingsLib/res/values-ky/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"карта13"</item>
<item msgid="8147982633566548515">"карта14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Система тандаганды колдонуу (демейки)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> аудио"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> аудио"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Система тандаганды колдонуу (демейки)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> аудио"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> аудио"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Система тандаганды колдонуу (демейки)"</item>
<item msgid="8003118270854840095">"44,1 кГц"</item>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index e85e6af..ea9bd86 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD форматындагы аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD форматындагы аудио"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Угуу аппараттары"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE аудио"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Угуу аппараттарына туташып турат"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO менен туташты"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE аудио менен туташты"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Медиа аудиого туташты"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Телефон аудиосуна туташты"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Файл өткөрүү серверине туташты"</string>
@@ -396,7 +396,7 @@
<string name="overlay_display_devices_title" msgid="5411894622334469607">"Көмөкчү экрандардын эмуляциясы"</string>
<string name="debug_applications_category" msgid="5394089406638954196">"Колдонмолор"</string>
<string name="immediately_destroy_activities" msgid="1826287490705167403">"Аракеттер сакталбасын"</string>
- <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"Колдонуучу чыгып кетери менен бардык аракеттер өчүрүлөт"</string>
+ <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"Колдонуучу чыгып кетери менен бардык аракеттер өчүп калат"</string>
<string name="app_process_limit_title" msgid="8361367869453043007">"Фондогу процесстер чеги"</string>
<string name="show_all_anrs" msgid="9160563836616468726">"Фондук режимдеги ANR"</string>
<string name="show_all_anrs_summary" msgid="8562788834431971392">"Фондогу колдонмо жооп бербей жатат деп билдирип турат"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Бир нече терезе режиминде өлчөмдү өзгөртүүгө уруксат берет (манифесттин маанилерине карабастан)"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Эркин формадагы терезелерди түзүүнү иштетүү"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Эркин формадагы терезелерди түзүү боюнча сынамык функциясы иштетилет."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Компьютер режими"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Камдык көчүрмөнүн сырсөзү"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Толук камдык көчүрмөлөр учурда корголгон эмес"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Иш тактасынын камдалган сырсөзүн өзгөртүү же алып салуу үчүн таптап коюңуз"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> кийин толук кубатталат"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> кийин толук кубатталат"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Кубаттоо убактылуу чектелген"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Белгисиз"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Кубатталууда"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ыкчам кубатталууда"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Жай кубатталууда"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Зымсыз кубатталууда"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Кубаттоо док бекети"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Кубат алган жок"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Туташты, кубатталган жок"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Кубатталды"</string>
@@ -602,7 +605,7 @@
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Конок сеансын баштапкы абалга келтиресизби?"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Бул аракет жаңы конок сеансын баштап, учурдагы сеанстагы бардык колдонмолорду жана алардагы нерселерди жок кылат"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"Конок режиминен чыгасызбы?"</string>
- <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Бул учурдагы конок сеансындагы колдонмолорду жана алардагы нерселерди жок кылат"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Учурдагы конок сеансындагы бардык колдонмолор менен алардагы нерселер өчүп калат"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Чыгуу"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Коноктун аракеттерин сактайсызбы?"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Учурдагы сеанстагы аракеттерди сактап же бардык колдонмолорду жана алардагы нерселерди жок кылсаңыз болот"</string>
@@ -611,7 +614,7 @@
<string name="guest_exit_button" msgid="5774985819191803960">"Конок режиминен чыгуу"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"Конок сеансын кайра коюу"</string>
<string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Конок режиминен чыгуу"</string>
- <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Чыксаңыз, бардык аракеттер өчүрүлөт"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Чыксаңыз, бардык аракеттер өчүп калат"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Чыгуудан мурун аракеттериңизди сактап же жок кылсаңыз болот"</string>
<string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Сеанстагы аракеттерди азыр өчүрсөңүз болот же чыгып баратып өчүрүп же сактап коюңуз"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сүрөткө тартуу"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Абанын сапаты"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Тышкы экранга чыгаруу маалыматы"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Үйдү көзөмөлдөө"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Профилдин сүрөтүн тандоо"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Демейки колдонуучунун сүрөтчөсү"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Аппараттык баскычтоп"</string>
diff --git a/packages/SettingsLib/res/values-lo/arrays.xml b/packages/SettingsLib/res/values-lo/arrays.xml
index 792ca39..f116e6f 100644
--- a/packages/SettingsLib/res/values-lo/arrays.xml
+++ b/packages/SettingsLib/res/values-lo/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"ໃຊ້ການເລືອກຂອງລະບົບ (ຄ່າເລີ່ມຕົ້ນ)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"ສຽງ <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"ສຽງ <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"ໃຊ້ການເລືອກຂອງລະບົບ (ຄ່າເລີ່ມຕົ້ນ)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"ສຽງ <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"ສຽງ <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"ໃຊ້ການເລືອກຂອງລະບົບ (ຄ່າເລີ່ມຕົ້ນ)"</item>
<item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index ace4276..10b814d 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"ສຽງ HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"ສຽງ HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"ອຸປະກອນຊ່ວຍຟັງ"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"ສຽງ LE"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ເຊື່ອມຕໍ່ຫາອຸປະກອນຊ່ວຍຟັງແລ້ວ"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"ເຊື່ອມຕໍ່ຫາ LE_AUDIO ແລ້ວ"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"ເຊື່ອມຕໍ່ຫາສຽງ LE ແລ້ວ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ເຊື່ອມຕໍ່ກັບສື່ດ້ານສຽງແລ້ວ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ເຊື່ອມຕໍ່ກັບສຽງໂທລະສັບແລ້ວ"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ເຊື່ອມຕໍ່ກັບເຊີບເວີໂອນຍ້າຍໄຟລ໌ແລ້ວ"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ເຮັດໃຫ້ທຸກການເຄື່ອນໄຫວສາມາດປັບຂະໜາດໄດ້ສຳລັບຫຼາຍໜ້າຈໍ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າ manifest."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"ເປີດໃຊ້ໜ້າຈໍຮູບແບບອິດສະຫຼະ"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"ເປີດໃຊ້ການຮອງຮັບໜ້າຈໍຮູບແບບອິດສະຫຼະແບບທົດລອງ."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"ໂໝດເດັສທັອບ"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນເດັສທັອບ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັສທັອບຍັງບໍ່ໄດ້ຮັບການປ້ອງກັນໃນເວລານີ້"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ແຕະເພື່ອປ່ຽນ ຫຼື ລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັສທັອບ"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"ຍັງເຫຼືອອີກ <xliff:g id="TIME">%1$s</xliff:g> ຈຶ່ງຈະສາກເຕັມ"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"ຍັງເຫຼືອອີກ <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ຈຶ່ງຈະສາກເຕັມ"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - ຈຳກັດການສາກໄຟຊົ່ວຄາວ"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"ບໍ່ຮູ້ຈັກ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ກຳລັງສາກໄຟ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ກຳລັງສາກໄຟດ່ວນ"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ກຳລັງສາກໄຟຊ້າໆ"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ກຳລັງສາກໄຟໄຮ້ສາຍ"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ກຳລັງສາກໄຟຜ່ານດັອກ"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ບໍ່ໄດ້ສາກໄຟ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ເຊື່ອມຕໍ່ແລ້ວ, ບໍ່ໄດ້ສາກໄຟ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ສາກເຕັມແລ້ວ"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"ຄຸນນະພາບອາກາດ"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"ຂໍ້ມູນການສົ່ງສັນຍານ"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ການຄວບຄຸມເຮືອນ"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ເລືອກຮູບໂປຣໄຟລ໌"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ໄອຄອນຜູ້ໃຊ້ເລີ່ມຕົ້ນ"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"ແປ້ນພິມພາຍນອກ"</string>
diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml
index 946f69c..c0aafdc 100644
--- a/packages/SettingsLib/res/values-lt/arrays.xml
+++ b/packages/SettingsLib/res/values-lt/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Naudoti sistemos pasirink. (numatytasis)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> garsas"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> garsas"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Naudoti sistemos pasirink. (numatytasis)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> garsas"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> garsas"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Naudoti sistemos pasirink. (numatytasis)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index b309db6..ce53dfe 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD garsas: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD garsas"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Klausos aparatai"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Prisijungta prie klausos aparatų"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Prisijungta prie LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Prisijungta prie „LE Audio“"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Prijungta prie medijos garso įrašo"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Prijungta prie telefono garso"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Prijungta prie failų perkėlimo serverio"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Nustatyti, kad visus veiksmus būtų galima atlikti kelių dydžių languose, nepaisant aprašo verčių."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Įgalinti laisvos formos langus"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Įgalinti eksperimentinių laisvos formos langų palaikymą."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Stalinio komp. režimas"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Viet. atsrg. kop. slapt."</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Šiuo metu visos vietinės atsarginės kopijos neapsaugotos"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Jei norite pakeisti ar pašalinti visų stalinio kompiuterio atsarginių kopijų slaptažodį, palieskite"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Liko <xliff:g id="TIME">%1$s</xliff:g>, kol bus visiškai įkrauta"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko <xliff:g id="TIME">%2$s</xliff:g>, kol bus visiškai įkrauta"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Įkrovimas laikinai apribotas"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nežinomas"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Kraunasi..."</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Greitai įkraunama"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Lėtai įkraunama"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Kraunama be laidų"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Įkrovimo dokas"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nekraunama"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Prijungta, neįkraunama"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Įkrauta"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Oro kokybė"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Perdav. informacija"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Namų sist. valdikl."</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Pasirinkite profilio nuotrauką"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Numatytojo naudotojo piktograma"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fizinė klaviatūra"</string>
diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml
index f4ae452..0f9ee52 100644
--- a/packages/SettingsLib/res/values-lv/arrays.xml
+++ b/packages/SettingsLib/res/values-lv/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Sistēmas atlases izmantošana (nokl.)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Sistēmas atlases izmantošana (nokl.)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Sistēmas atlases izmantošana (nokl.)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 6bbc051..df91791 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Dzirdes aparāti"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO profils"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Izveidots savienojums ar dzirdes aparātiem"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Izveidots savienojums ar LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Izveidots savienojums ar LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Savienots ar multivides audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Savienots ar tālruņa audio"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Savienots ar failu pārsūtīšanas serveri"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Pielāgot visas darbības vairāku logu režīmam neatkarīgi no vērtībām manifestā."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Iespējot brīvās formas logus"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Iespējot eksperimentālo brīvās formas logu atbalstu."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Darbvirsmas režīms"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Datora dublējuma parole"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Darbvirsmas pilnie dublējumi pašlaik nav aizsargāti."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Pieskarieties, lai mainītu vai noņemtu paroli pilniem datora dublējumiem."</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> līdz pilnai uzlādei"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai uzlādei"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> — uzlāde īslaicīgi ierobežota"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nezināms"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Uzlāde"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Notiek ātrā uzlāde"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Notiek lēnā uzlāde"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bezvadu uzlāde"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Uzlādes doks"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenotiek uzlāde"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ierīce pievienota, uzlāde nenotiek"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Uzlādēts"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Gaisa kvalitāte"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Apraides informācija"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Mājas kontrolierīces"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profila attēla izvēle"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Noklusējuma lietotāja ikona"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fiziskā tastatūra"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index eb9cbfd..7f82835 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-аудио"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Слушни помагала"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE-аудио"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Поврзано со слушни помагала"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Поврзано на LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Поврзано на LE-аудио"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Поврзан со аудио на медиуми"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Поврзан со аудио на телефон"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Поврзан со сервер за пренос на датотеки"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Направете сите активности да бидат со променлива големина за повеќе прозорци, без разлика на вредностите на манифестот."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Овозможи прозорци со слободна форма"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Овозможи поддршка за експериментални прозорци со слободна форма."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Режим за компјутер"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Лозинка за бекап на компјутер"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Целосниот бекап на компјутерот во моментов не е заштитен"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Допрете за да се промени или отстрани лозинката за целосен бекап на компјутерот"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до полна батерија"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> до полна батерија"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Полнењето е привремено ограничено"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Се полни"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо полнење"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Бавно полнење"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Се полни безжично"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Се полни на док"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не се полни"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Поврзано, не се полни"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Полна"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 3d99eda..43040ef 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ഓഡിയോ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ഓഡിയോ"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"ശ്രവണ സഹായികൾ"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE ഓഡിയോ"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ശ്രവണ സഹായികളിലേക്ക് കണക്റ്റ് ചെയ്തു"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO-യിലേക്ക് കണക്റ്റ് ചെയ്തു"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ഓഡിയോയിലേക്ക് കണക്റ്റ് ചെയ്തു"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"മീഡിയ ഓഡിയോയിലേക്ക് കണക്റ്റുചെയ്തു"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ഫോൺ ഓഡിയോയിൽ കണക്റ്റുചെയ്തു"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ഫയൽ കൈമാറ്റ സെർവറിലേക്ക് കണക്റ്റുചെയ്തു"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ ആക്ടിവിറ്റികളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലുപ്പം മാറ്റുക."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"ഫ്രീഫോം വിൻഡോകൾ പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"പരീക്ഷണാത്മക ഫ്രീഫോം വിൻഡോകൾക്കുള്ള പിന്തുണ പ്രവർത്തനക്ഷമമാക്കുക."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"ഡെസ്ക്ടോപ്പ് മോഡ്"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ഡെസ്ക്ടോപ്പ് ബാക്കപ്പ് പാസ്വേഡ്"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ഡെസ്ക്ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾ നിലവിൽ പരിരക്ഷിച്ചിട്ടില്ല"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ഡെസ്ക്ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾക്കായി പാസ്വേഡുകൾ മാറ്റാനോ നീക്കംചെയ്യാനോ ടാപ്പുചെയ്യുക"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"പൂർണ്ണമാകാൻ <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - പൂർണ്ണമാകാൻ <xliff:g id="TIME">%2$s</xliff:g> ശേഷിക്കുന്നു"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - ചാർജിംഗ് താൽക്കാലികമായി പരിമിതപ്പെടുത്തിയിരിക്കുന്നു"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"അജ്ഞാതം"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ചാർജ് ചെയ്യുന്നു"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"അതിവേഗ ചാർജിംഗ്"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"പതുക്കെയുള്ള ചാർജിംഗ്"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"വയർലെസായി ചാർജുചെയ്യുന്നു"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ചാർജിംഗ് ഡോക്ക്"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ചാർജ്ജുചെയ്യുന്നില്ല"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"കണക്റ്റ് ചെയ്തിരിക്കുന്നു, ചാർജ് ചെയ്യുന്നില്ല"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ചാർജായി"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index c2f241c..ad8b6fd 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD аудио: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD аудио"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Сонсголын төхөөрөмж"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_АУДИО"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE аудио"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Сонсголын төхөөрөмжтэй холбосон"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_АУДИОНД холбогдлоо"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE аудионд холбогдсон"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Медиа аудиод холбогдсон"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Утасны аудид холбогдсон"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Файл дамжуулах серверт холбогдсон"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааны хэмжээг олон цонхонд өөрчилж болохуйц болгоно уу."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Чөлөөт хэлбэрийн цонхыг идэвхжүүлэх"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Туршилтын чөлөөт хэлбэрийн цонхны дэмжлэгийг идэвхжүүлнэ үү."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Дэлгэцийн горим"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Компьютерын нөөцлөлтийн нууц үг"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Компьютерын бүрэн нөөцлөлт одоогоор хамгаалалтгүй байна"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Компьютерийн бүтэн нөөцлөлтийн нууц үгийг өөрчлөх, устгах бол дарна уу"</string>
@@ -447,8 +448,8 @@
<string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"Дьютераномаль (улаан-ногоон)"</string>
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномаль (улаан-ногоон)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомаль (цэнхэр-шар)"</string>
- <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Өнгө тохируулах"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Өнгөний засвар нь таныг дараахыг хийхийг хүсэх үед хэрэгтэй байж болно:<br/> <ol> <li>&nbsp;Өнгөнүүдийг илүү нарийвчилж харах</li> <li>&nbsp;Төвлөрөхийн тулд өнгөнүүдийг хасах</li> </ol>"</string>
+ <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Өнгө тохируулга"</string>
+ <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Өнгө тохируулга нь таныг дараахыг хийхийг хүсэх үед хэрэгтэй байж болно:<br/> <ol> <li>&nbsp;Өнгөнүүдийг илүү нарийвчилж харах</li> <li>&nbsp;Төвлөрөхийн тулд өнгөнүүдийг хасах</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Дүүрэх хүртэл <xliff:g id="TIME">%1$s</xliff:g> үлдсэн"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - дүүрэх хүртэл <xliff:g id="TIME">%2$s</xliff:g> үлдсэн"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Цэнэглэхийг түр зуур хязгаарласан"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Тодорхойгүй"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Цэнэглэж байна"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хурдан цэнэглэж байна"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Удаан цэнэглэж байна"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Утасгүй цэнэглэж байна"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Цэнэглэх холбогч"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Цэнэглэхгүй байна"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Холбогдсон, цэнэглээгүй байна"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Цэнэглэсэн"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 13ea9c9..be5222a 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ऑडिओ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ऑडिओ"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"श्रवणयंत्रे"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE ऑडिओ"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"श्रवण यंत्रांशी कनेक्ट केले आहे"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO शी कनेक्ट केले आहे"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ऑडिओशी कनेक्ट केले आहे"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"मीडिया ऑडिओवर कनेक्ट केले"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"फोन ऑडिओ वर कनेक्ट केले"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"फाइल स्थानांतर सर्व्हरवर कनेक्ट केले"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"मॅनिफेस्ट मूल्ये काहीही असू देत, एकाहून अधिक विंडोसाठी सर्व अॅक्टिव्हिटीचा आकार बदलण्यायोग्य करा."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"freeform विंडो सुरू करा"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी सपोर्ट सुरू करा."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"डेस्कटॉप मोड"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"डेस्कटॉप बॅकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"डेस्कटॉप पूर्ण बॅक अप सध्या संरक्षित नाहीत"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला पासवर्ड बदलण्यासाठी किंवा काढण्यासाठी टॅप करा"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%1$s</xliff:g> शिल्लक आहेत"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%2$s</xliff:g> शिल्लक आहे"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> • चार्जिंग तात्पुरते मर्यादित आहे"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज होत आहे"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"वेगाने चार्ज होत आहे"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"हळू चार्ज होत आहे"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेसने चार्ज होत आहे"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"चार्जिंग डॉक"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज होत नाही"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"कनेक्ट केले, चार्ज होत नाही"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"चार्ज झाली"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 9ff2170..cadc5cf 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Alat Bantu Dengar"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Disambungkan pada Alat Bantu Dengar"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Disambungkan kepada LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Disambungkan kepada LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Disambungkan ke audio media"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Disambungkan ke audio telefon"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Bersambung ke pelayan pemindahan fail"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Bolehkan semua saiz aktiviti diubah untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Dayakan tetingkap bentuk bebas"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Dayakan sokongan untuk tetingkap bentuk bebas percubaan."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Mod desktop"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Kata laluan sandaran komputer meja"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Sandaran penuh komputer meja tidak dilindungi pada masa ini"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ketik untuk menukar atau mengalih keluar kata laluan untuk sandaran penuh desktop"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> lagi sebelum penuh"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi sebelum penuh"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengecasan terhad sementara"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Mengecas"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengecas dgn cepat"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Mengecas perlahan"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Mengecas tanpa wayar"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Dok Pengecasan"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Tidak mengecas"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Bersambung, tidak mengecas"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Sudah dicas"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 0492dac..0c49387 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD အသံ- <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD အသံ"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"နားကြားကိရိယာ"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE အသံ"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"နားကြားကိရိယာနှင့် ချိတ်ဆက်ပြီးပါပြီ"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO နှင့် ချိတ်ဆက်ထားသည်"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE အသံနှင့် ချိတ်ဆက်ထားသည်"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"မီဒီယာအသံအား ချိတ်ဆက်ရန်"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ဖုန်းအသံအား ချိတ်ဆက်ရန်"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ဖိုင်လွှဲပြောင်းမည့်ဆာဗာနှင့် ချိတ်ဆက်ထားပြီး"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"သတ်မှတ်တန်ဖိုး မည်သို့ပင်ရှိစေ ဝင်းဒိုးများ၏ လုပ်ဆောင်မှုအားလုံးကို အရွယ်အစားပြင်သည်။"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"ရွှေ့နိုင်ပြင်နိုင်သော ဝင်းဒိုးများ ဖွင့်ရန်"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"ပုံစံမျိုးစုံဝင်းဒိုးများ စမ်းသပ်မှုအတွက် အထောက်အပံ့ကို ဖွင့်ပါ"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"ဒက်စ်တော့မုဒ်"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ဒက်စ်တော့ အရန်စကားဝှက်"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ဒက်စ်တော့ အရန်သိမ်းဆည်းခြင်းအားလုံးကို လောလောဆယ် ကာကွယ်မထားပါ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ဒက်စ်တော့ အပြည့်အဝ အရန်သိမ်းခြင်းအတွက် စကားဝှက်ကို ပြောင်းရန် သို့မဟုတ် ဖယ်ရှားရန် တို့ပါ။"</string>
@@ -448,7 +449,7 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (အနီ-အစိမ်း)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (အပြာ-အဝါ)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"အရောင်ပြင်ဆင်မှု"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"အရောင် အမှန်ပြင်ခြင်းသည် အောက်ပါတို့အတွက် အသုံးဝင်နိုင်သည်-<br/> <ol> <li>&nbsp;အရောင်များကို ပိုမိုမှန်ကန်စွာ ကြည့်ရှုခြင်း&lt</li> <li>&nbsp;အာရုံစိုက်နိုင်ရန် အရောင်များ ဖယ်ရှားခြင်း</li> </ol>"</string>
+ <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"အရောင် အမှန်ပြင်ခြင်းသည် အောက်ပါတို့အတွက် အသုံးဝင်နိုင်သည်-<br/> <ol> <li>&nbsp;အရောင်များကို ပိုမိုမှန်ကန်စွာ ကြည့်ရှုခြင်း</li> <li>&nbsp;အာရုံစိုက်နိုင်ရန် အရောင်များ ဖယ်ရှားခြင်း</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"အားပြည့်ရန် <xliff:g id="TIME">%1$s</xliff:g> လိုသည်"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"အားပြည့်ရန် <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> လိုသည်"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားသွင်းခြင်းကို လောလောဆယ် ကန့်သတ်ထားသည်"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"မသိ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"အားသွင်းနေပါသည်"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"အမြန် အားသွင်းနေသည်"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"နှေးကွေးစွာ အားသွင်း"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ကြိုးမဲ့ အားသွင်းနေသည်"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"အားသွင်းအထိုင်"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"အားသွင်းမနေပါ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ချိတ်ဆက်ထားသည်၊ အားသွင်းမနေပါ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"အားသွင်းပြီးပါပြီ"</string>
@@ -591,7 +594,7 @@
<string name="add_guest_failed" msgid="8074548434469843443">"ဧည့်သည်သစ် ပြုလုပ်၍မရပါ"</string>
<string name="user_nickname" msgid="262624187455825083">"နာမည်ပြောင်"</string>
<string name="user_add_user" msgid="7876449291500212468">"အသုံးပြုသူ ထည့်ရန်"</string>
- <string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည့် ထည့်ရန်"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည် ထည့်ရန်"</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>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 7f67bd2..6ca0cc3 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-lyd: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-lyd"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Høreapparater"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE-lyd"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Koblet til høreapparater"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Koblet til LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Koblet til LE-lyd"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Koblet til medielyd"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Koblet til telefonlyd"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Koblet til tjener for filoverføring"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gjør at alle aktiviteter kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Slå på vinduer i fritt format"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Slå på støtte for vinduer i eksperimentelt fritt format."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Skrivebordmodus"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Passord for sikkerhetskopiering på datamaskin"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Fullstendig sikkerhetskopiering på datamaskin er ikke beskyttet"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Trykk for å endre eller fjerne passordet for fullstendige sikkerhetskopier på datamaskinen"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Fulladet om <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – Fulladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Lading er midlertidig begrenset"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ukjent"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Lader"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Lader raskt"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Lader sakte"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Lader trådløst"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Ladedokk"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Lader ikke"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Tilkoblet, lader ikke"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Ladet"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 522b5ee..88bdba4 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD अडियो: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD अडियो"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"श्रवण यन्त्रहरू"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE अडियो"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"श्रवण यन्त्रहरूमा जडान गरियो"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO मा कनेक्ट गरिएको छ"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE अडियोमा कनेक्ट गरिएको छ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"मिडिया अडियोसँग जडित"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"फोन अडियोमा जडान गरियो"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"फाइल ट्रान्सफर सर्भरमा जडान गरियो"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"तोकिएको नियमको ख्याल नगरी एपलाई एकभन्दा बढी विन्डोमा रिसाइज गर्न सकिने बनाइयोस्।"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"फ्रिफर्म विन्डोहरू अन गरियोस्"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"प्रयोगात्मक फ्रिफर्म विन्डोहरू चल्ने बनाइयोस्"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"डेस्कटप मोड"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"डेस्कटप ब्याकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"हाल डेस्कटपका सबै ब्याकअप पासवर्ड सुरक्षित छैनन्"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"डेस्कटप पूर्ण ब्याकअपको लागि पासवर्ड बदल्न वा हटाउन ट्याप गर्नुहोस्"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"पूरा चार्ज हुन <xliff:g id="TIME">%1$s</xliff:g> लाग्ने छ"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - पूरा चार्ज हुन <xliff:g id="TIME">%2$s</xliff:g> लाग्ने छ"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिङ केही समयका लागि सीमित पारिएको छ"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हुँदै छ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"द्रुत गतिमा चार्ज गरिँदै छ"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ढिलो चार्ज हुँदै छ"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेस तरिकाले चार्ज गरिँदै छ"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"डक चार्ज हुँदै छ"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज भइरहेको छैन"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"कनेक्ट गरिएको छ, चार्ज भइरहेको छैन"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"चार्ज भयो"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 9a90a7f..1183630 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hoortoestellen"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Le Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Verbonden met hoortoestellen"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Verbonden met LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Verbonden met LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Verbonden met audio van medium"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Verbonden met audio van telefoon"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Verbonden met server voor bestandsoverdracht"</string>
@@ -184,7 +184,7 @@
<string name="launch_defaults_some" msgid="3631650616557252926">"Enkele standaardwaarden ingesteld"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"Geen standaardwaarden ingesteld"</string>
<string name="tts_settings" msgid="8130616705989351312">"Instellingen tekst-naar-spraak"</string>
- <string name="tts_settings_title" msgid="7602210956640483039">"Spraakuitvoer"</string>
+ <string name="tts_settings_title" msgid="7602210956640483039">"Tekst-naar-spraakuitvoer"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Spreeksnelheid"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"Snelheid waarmee de tekst wordt gesproken"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"Toonhoogte"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Maak het formaat van alle activiteiten aanpasbaar, ongeacht de manifestwaarden"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Vensters met vrije vorm aanzetten"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Zet ondersteuning voor vensters met experimentele vrije vorm aan"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Desktopmodus"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Wachtwoord desktopback-up"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Volledige back-ups naar desktops zijn momenteel niet beveiligd"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tik om het wachtwoord voor volledige back-ups naar desktops te wijzigen of te verwijderen"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Vol over <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - vol over <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Opladen tijdelijk beperkt"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Opladen"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Snel opladen"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Langzaam opladen"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Draadloos opladen"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Oplaaddock"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Wordt niet opgeladen"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Verbonden, wordt niet opgeladen"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Opgeladen"</string>
@@ -600,7 +603,7 @@
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Verwijderen"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Gast resetten…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Gastsessie resetten?"</string>
- <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Hierdoor wordt een nieuwe gastsessie gestart en worden alle apps en gegevens van de huidige sessie verwijderd"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Hiermee start een nieuwe gastsessie en worden alle apps en gegevens van de huidige sessie verwijderd"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"Gastmodus sluiten?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Hierdoor worden apps en gegevens van de huidige gastsessie verwijderd"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Sluiten"</string>
diff --git a/packages/SettingsLib/res/values-or/arrays.xml b/packages/SettingsLib/res/values-or/arrays.xml
index d42aeaf..a6c40b0 100644
--- a/packages/SettingsLib/res/values-or/arrays.xml
+++ b/packages/SettingsLib/res/values-or/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"ସିଷ୍ଟମ୍ ଚୟନ ବ୍ୟବହାର କରନ୍ତୁ (ଡିଫଲ୍ଟ)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ଅଡିଓ"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ଅଡିଓ"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"ସିଷ୍ଟମ୍ର ଚୟନ (ଡିଫଲ୍ଟ୍) ବ୍ୟବହାର କରନ୍ତୁ"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ଅଡିଓ"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ଅଡିଓ"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"ସିଷ୍ଟମ୍ର ଚୟନ (ଡିଫଲ୍ଟ୍) ବ୍ୟବହାର କରନ୍ତୁ"</item>
<item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 65813a7..a949dc9 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -116,18 +116,18 @@
<string name="bluetooth_profile_headset" msgid="5395952236133499331">"ଫୋନ୍ କଲ୍ଗୁଡ଼ିକ"</string>
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"ଇନ୍ପୁଟ୍ ଡିଭାଇସ୍"</string>
- <string name="bluetooth_profile_pan" msgid="1006235139308318188">"ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍"</string>
+ <string name="bluetooth_profile_pan" msgid="1006235139308318188">"ଇଣ୍ଟରନେଟ ଆକ୍ସେସ"</string>
<string name="bluetooth_profile_pbap" msgid="4262303387989406171">"କଣ୍ଟାକ୍ଟ ଏବଂ କଲ ଇତିହାସ ସେୟାରିଂ"</string>
<string name="bluetooth_profile_pbap_summary" msgid="6466456791354759132">"କଣ୍ଟାକ୍ଟ ଏବଂ କଲ ଇତିହାସ ସେୟାରିଂ ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ଶେୟାରିଙ୍ଗ"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"ଟେକ୍ସଟ୍ ମେସେଜ୍"</string>
- <string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM ଆକ୍ସେସ୍"</string>
+ <string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM ଆକ୍ସେସ"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ଅଡିଓ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ଅଡିଓ"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE ଅଡିଓ"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ଶ୍ରବଣ ଯନ୍ତ୍ରକୁ ସଂଯୋଗ ହୋଇଛି"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO ସହ ସଂଯୋଗ କରାଯାଇଛି"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ଅଡିଓ ସହ କନେକ୍ଟ କରାଯାଇଛି"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ମିଡିଆ ଅଡିଓ ସହ ସଂଯୁକ୍ତ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ଫୋନ୍ ଅଡିଓ ସହିତ ସଂଯୁକ୍ତ"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍ ସର୍ଭର୍ ସହ ସଂଯୁକ୍ତ"</string>
@@ -156,7 +156,7 @@
<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>
<string name="bluetooth_talkback_headset" msgid="3406852564400882682">"ହେଡ୍ସେଟ୍"</string>
- <string name="bluetooth_talkback_phone" msgid="868393783858123880">"ଫୋନ୍"</string>
+ <string name="bluetooth_talkback_phone" msgid="868393783858123880">"ଫୋନ"</string>
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ଇମେଜିଙ୍ଗ"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"ହେଡ୍ଫୋନ୍"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ଇନ୍ପୁଟ୍ ଉପକରଣ"</string>
@@ -246,7 +246,7 @@
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ଛଅ ଡିଜିଟ୍ କୋଡ୍ ବ୍ୟବହାର କରି ନୂଆ ଡିଭାଇସଗୁଡ଼ିକୁ ପେୟାର୍ କରନ୍ତୁ"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"ପେୟାର୍ ହୋଇଥିବା ଡିଭାଇସଗୁଡ଼ିକ"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"ବର୍ତ୍ତମାନ ସଂଯୁକ୍ତ ଅଛି"</string>
- <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"ଡିଭାଇସ୍ ବିବରଣୀ"</string>
+ <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"ଡିଭାଇସର ବିବରଣୀ"</string>
<string name="adb_device_forget" msgid="193072400783068417">"ଭୁଲିଯାଆନ୍ତୁ"</string>
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"ଡିଭାଇସ୍ ଫିଙ୍ଗରପ୍ରିଣ୍ଟ: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"ସଂଯୋଗ ବିଫଳ ହେଲା"</string>
@@ -394,7 +394,7 @@
<string name="transition_animation_scale_title" msgid="1278477690695439337">"ଟ୍ରାଞ୍ଜିସନ୍ ଆନିମେସନ୍ ସ୍କେଲ୍"</string>
<string name="animator_duration_scale_title" msgid="7082913931326085176">"ଆନିମେଟର୍ ଅବଧି ସ୍କେଲ୍"</string>
<string name="overlay_display_devices_title" msgid="5411894622334469607">"ସେକେଣ୍ଡାରୀ ଡିସ୍ପ୍ଲେ ସିମୁଲେଟ୍ କରନ୍ତୁ"</string>
- <string name="debug_applications_category" msgid="5394089406638954196">"ଆପ୍ଗୁଡ଼ିକ"</string>
+ <string name="debug_applications_category" msgid="5394089406638954196">"ଆପ୍ସ"</string>
<string name="immediately_destroy_activities" msgid="1826287490705167403">"କାର୍ଯ୍ୟକଳାପଗୁଡ଼ିକୁ ରଖନ୍ତୁ ନାହିଁ"</string>
<string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"ୟୁଜର୍ ଏହାକୁ ଛାଡ଼ିବା କ୍ଷଣି ସମସ୍ତ କାର୍ଯ୍ୟକଳାପ ନଷ୍ଟ କରିଦିଅନ୍ତୁ"</string>
<string name="app_process_limit_title" msgid="8361367869453043007">"ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡ ପ୍ରୋସେସ୍ ସୀମା"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ୱିଣ୍ଡୋ ହିସାବରେ କାର୍ଯ୍ୟକଳାପଗୁଡ଼ିକୁ ବଦଳାନ୍ତୁ, ସେଗୁଡ଼ିକର ମାନିଫେଷ୍ଟ ଭାଲ୍ୟୁ ଯାହା ହୋଇଥାଉ ନା କାହିଁକି"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"ଫ୍ରୀଫର୍ମ ୱିଣ୍ଡୋ ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"ପରୀକ୍ଷାମୂଳକ ଫ୍ରୀଫର୍ମ ୱିଣ୍ଡୋସ୍ ପାଇଁ ସପୋର୍ଟ ସକ୍ଷମ କରନ୍ତୁ।"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"ଡେସ୍କଟପ ମୋଡ"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ଡେସ୍କଟପ୍ ବ୍ୟାକଅପ୍ ପାସ୍ୱର୍ଡ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ଡେସ୍କଟପ୍ର ସମ୍ପୂର୍ଣ୍ଣ ବ୍ୟାକଅପ୍ଗୁଡ଼ିକ ବର୍ତ୍ତମାନ ସୁରକ୍ଷିତ ନୁହେଁ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ଡେସ୍କଟପ୍ର ସମ୍ପୂର୍ଣ୍ଣ ବ୍ୟାକ୍ଅପ୍ ପାଇଁ ପାସ୍ୱର୍ଡ ବଦଳାଇବା କିମ୍ୱା କାଢ଼ିଦେବା ନିମନ୍ତେ ଟାପ୍ କରନ୍ତୁ"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"ପୂର୍ଣ୍ଣ ହେବାକୁ ଆଉ <xliff:g id="TIME">%1$s</xliff:g> ବାକି ଅଛି"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - ପୂର୍ଣ୍ଣ ହେବାକୁ ଆଉ <xliff:g id="TIME">%2$s</xliff:g> ବାକି ଅଛି"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - ଚାର୍ଜିଂ ଅସ୍ଥାୟୀ ଭାବେ ସୀମିତ କରାଯାଇଛି"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"ଅଜ୍ଞାତ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ଚାର୍ଜ ହେଉଛି"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ଶୀଘ୍ର ଚାର୍ଜ ହେଉଛି"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ଧୀରେ ଚାର୍ଜ ହେଉଛି"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ୱେୟରଲେସ ଭାବେ ଚାର୍ଜିଂ"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ଡକ ଚାର୍ଜ ହେଉଛି"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ଚାର୍ଜ ହେଉନାହିଁ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ସଂଯୋଗ କରାଯାଇଛି, ଚାର୍ଜ ହେଉନାହିଁ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ଚାର୍ଜ ହୋଇଯାଇଛି"</string>
@@ -551,7 +554,7 @@
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string>
<string name="help_label" msgid="3528360748637781274">"ସାହାଯ୍ୟ ଓ ମତାମତ"</string>
- <string name="storage_category" msgid="2287342585424631813">"ଷ୍ଟୋରେଜ୍"</string>
+ <string name="storage_category" msgid="2287342585424631813">"ଷ୍ଟୋରେଜ"</string>
<string name="shared_data_title" msgid="1017034836800864953">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ଦେଖନ୍ତୁ ଏବଂ ଏହାକୁ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
<string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ କୌଣସି ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ନାହିଁ।"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"ବାୟୁର ଗୁଣବତ୍ତା"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"କାଷ୍ଟ ସୂଚନା"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"ହୋମ କଣ୍ଟ୍ରୋଲ"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"ସ୍ମାର୍ଟସ୍ପେସ"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"ଏକ ପ୍ରୋଫାଇଲ ଛବି ବାଛନ୍ତୁ"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"ଡିଫଲ୍ଟ ଉପଯୋଗକର୍ତ୍ତା ଆଇକନ"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"ଫିଜିକାଲ କୀବୋର୍ଡ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index e111f8a..4d16cec 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ਆਡੀਓ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ਆਡੀਓ"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"ਸੁਣਨ ਦੇ ਸਾਧਨ"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE ਆਡੀਓ"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ਸੁਣਨ ਦੇ ਸਾਧਨਾਂ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ਆਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"ਮੀਡੀਆ ਆਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ਫ਼ੋਨ ਔਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ਫਾਈਲ ਟ੍ਰਾਂਸਫ਼ਰ ਸਰਵਰ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
@@ -337,7 +337,7 @@
<string name="dev_settings_warning_message" msgid="37741686486073668">"ਇਹ ਸੈਟਿੰਗਾਂ ਕੇਵਲ ਵਿਕਾਸਕਾਰ ਦੀ ਵਰਤੋਂ ਲਈ ਹਨ। ਇਹ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਅਤੇ ਇਸਤੇ ਮੌਜੂਦ ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ ਬ੍ਰੇਕ ਕਰਨ ਜਾਂ ਦੁਰਵਿਵਹਾਰ ਕਰਨ ਦਾ ਕਾਰਨ ਬਣ ਸਕਦੇ ਹਨ।"</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB \'ਤੇ ਐਪਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"ADB/ADT ਰਾਹੀਂ ਸਥਾਪਤ ਕੀਤੀਆਂ ਐਪਾਂ ਦੀ ਹਾਨੀਕਾਰਕ ਵਿਵਹਾਰ ਲਈ ਜਾਂਚ ਕਰੋ।"</string>
- <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਦਿਖਾਈਆਂ ਜਾਣਗੀਆਂ (ਸਿਰਫ਼ MAC ਪਤੇ)"</string>
+ <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸ ਦਿਖਾਏ ਜਾਣਗੇ (ਸਿਰਫ਼ MAC ਪਤੇ)"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"ਰਿਮੋਟ ਡੀਵਾਈਸਾਂ ਨਾਲ ਅਵਾਜ਼ੀ ਸਮੱਸਿਆਵਾਂ ਜਿਵੇਂ ਕਿ ਨਾ ਪਸੰਦ ਕੀਤੀ ਜਾਣ ਵਾਲੀ ਉੱਚੀ ਅਵਾਜ਼ ਜਾਂ ਕੰਟਰੋਲ ਦੀ ਕਮੀ ਵਰਗੀ ਹਾਲਤ ਵਿੱਚ ਬਲੂਟੁੱਥ ਪੂਰਨ ਅਵਾਜ਼ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ।"</string>
<string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"ਬਲੂਟੁੱਥ Gabeldorsche ਵਿਸ਼ੇਸ਼ਤਾ ਸਟੈਕ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ।"</string>
<string name="enhanced_connectivity_summary" msgid="1576414159820676330">"ਵਿਸਤ੍ਰਿਤ ਕਨੈਕਟੀਵਿਟੀ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ।"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ਮੈਨੀਫ਼ੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਆਕਾਰ ਬਦਲਣਯੋਗ ਬਣਾਓ।"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਜ਼ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"ਪ੍ਰਯੋਗਮਈ ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਜ਼ ਲਈ ਸਮਰਥਨ ਨੂੰ ਚਾਲੂ ਕਰੋ।"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"ਡੈਸਕਟਾਪ ਮੋਡ"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ਡੈਸਕਟਾਪ ਬੈਕਅੱਪ ਪਾਸਵਰਡ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ਡੈਸਕਟਾਪ ਦੇ ਪੂਰੇ ਬੈਕਅੱਪ ਇਸ ਵੇਲੇ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਹਨ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ਡੈਸਕਟਾਪ ਦੇ ਮੁਕੰਮਲ ਬੈਕਅੱਪਾਂ ਲਈ ਪਾਸਵਰਡ ਨੂੰ ਬਦਲਣ ਜਾਂ ਹਟਾਉਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"ਬੈਟਰੀ ਪੂਰੀ ਚਾਰਜ ਹੋਣ ਵਿੱਚ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਬੈਟਰੀ ਪੂਰੀ ਚਾਰਜ ਹੋਣ ਵਿੱਚ <xliff:g id="TIME">%2$s</xliff:g> ਬਾਕੀ"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਚਾਰਜਿੰਗ ਕੁਝ ਸਮੇਂ ਲਈ ਰੋਕੀ ਗਈ"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"ਅਗਿਆਤ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ਤੇਜ਼ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ਬਿਨਾਂ ਤਾਰ ਤੋਂ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ਡੌਕ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"ਕਨੈਕਟ ਹੈ, ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਹੀ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ਚਾਰਜ ਹੋ ਗਈ"</string>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index f0453d1..71ecd46 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Używaj wyboru systemu (domyślnie)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Używaj wyboru systemu (domyślnie)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Używaj wyboru systemu (domyślnie)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 64d7af0..cd8b6fb 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Dźwięk HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Dźwięk HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparaty słuchowe"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Połączono z aparatami słuchowymi"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Połączono z LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Połączono z LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Połączono z funkcją audio multimediów"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Połączono z funkcją audio telefonu"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Połączono z serwerem transferu plików"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Zezwalaj na zmianę rozmiaru wszystkich okien aktywności w trybie wielu okien niezależnie od ustawień w pliku manifestu"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Włącz dowolny rozmiar okien"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Włącz obsługę eksperymentalnej funkcji dowolnego rozmiaru okien"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Tryb pulpitu"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Hasło kopii zapasowej"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Pełne kopie zapasowe na komputerze nie są obecnie chronione"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dotknij, by zmienić lub usunąć hasło pełnych kopii zapasowych na komputerze."</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do pełnego naładowania"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ładowanie tymczasowo ograniczone"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nieznane"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Ładowanie"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Szybkie ładowanie"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Wolne ładowanie"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Ładowanie bezprzewodowe"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Ładowanie na stacji dokującej"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nie podłączony"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Podłączono, brak ładowania"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Naładowana"</string>
@@ -603,7 +606,7 @@
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Zostanie uruchomiona nowa sesja gościa. Wszystkie aplikacje i dane z obecnej sesji zostaną usunięte."</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"Zamknąć tryb gościa?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Wszystkie aplikacje i dane z obecnej sesji gościa zostaną usunięte."</string>
- <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Wyjdź"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Zamknij"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Zapisać aktywność gościa?"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Możesz zapisać aktywność z obecnej sesji lub usunąć wszystkie aplikacje i dane"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Usuń"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Jakość powietrza"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Obsada"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Sterowanie domem"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Wybierz zdjęcie profilowe"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikona domyślnego użytkownika"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Klawiatura fizyczna"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 8c1e83d..4e1b1dd 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Áudio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparelhos auditivos"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Áudio de baixa energia"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectado a aparelhos auditivos"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Conectado a LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado ao perfil Áudio de baixa energia"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado ao áudio da mídia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado ao áudio do smartphone"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Conectado ao servidor de transferência de arquivo"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Ativar janelas de forma livre"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ativar a compatibilidade com janelas experimentais de forma livre."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Modo área de trabalho"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Senha de backup local"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Os backups completos não estão protegidos no momento"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> até a conclusão"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> até a conclusão"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> (carregamento temporariamente limitado)"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Carregando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregando rápido"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carregando devagar"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carregando sem fio"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de carregamento"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está carregando"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado sem carregar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 63ce593d..9215ce3 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Áudio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparelhos auditivos"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Ligado a aparelhos auditivos"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Ligado a LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Ligado a LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ligado ao áudio de multimédia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ligado ao áudio do telefone"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Ligado ao servidor de transferência de ficheiros"</string>
@@ -190,7 +190,7 @@
<string name="tts_default_pitch_title" msgid="6988592215554485479">"Tonalidade"</string>
<string name="tts_default_pitch_summary" msgid="9132719475281551884">"Afeta o tom da voz sintetizada"</string>
<string name="tts_default_lang_title" msgid="4698933575028098940">"Idioma"</string>
- <string name="tts_lang_use_system" msgid="6312945299804012406">"Utilizar idioma do sistema"</string>
+ <string name="tts_lang_use_system" msgid="6312945299804012406">"Usar idioma do sistema"</string>
<string name="tts_lang_not_selected" msgid="7927823081096056147">"Idioma não selecionado"</string>
<string name="tts_default_lang_summary" msgid="9042620014800063470">"Define a voz do idioma específico para o texto lido"</string>
<string name="tts_play_example_title" msgid="1599468547216481684">"Ouvir um exemplo"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Ativar janelas de forma livre"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ativar a compatibilidade com janelas de forma livre experimentais."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Ambiente de trabalho"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Palavra-passe cópia do computador"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"As cópias de segurança completas no ambiente de trabalho não estão atualmente protegidas"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tocar para alterar ou remover a palavra-passe para cópias de segurança completas no ambiente de trabalho"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> até à carga máxima"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> até à carga máxima"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Carregamento limitado temporariamente"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"A carregar"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregamento rápido"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carregamento lento"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"A carregar sem fios"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Est. ancor. carreg."</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está a carregar"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ligado, não está a carregar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 8c1e83d..4e1b1dd 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Áudio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparelhos auditivos"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Áudio de baixa energia"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectado a aparelhos auditivos"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Conectado a LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectado ao perfil Áudio de baixa energia"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectado ao áudio da mídia"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectado ao áudio do smartphone"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Conectado ao servidor de transferência de arquivo"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Ativar janelas de forma livre"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ativar a compatibilidade com janelas experimentais de forma livre."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Modo área de trabalho"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Senha de backup local"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Os backups completos não estão protegidos no momento"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> até a conclusão"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> até a conclusão"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> (carregamento temporariamente limitado)"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Carregando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregando rápido"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carregando devagar"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carregando sem fio"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Base de carregamento"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está carregando"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado sem carregar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 4702b6a..3c81199 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparate auditive"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Conectat la aparatul auditiv"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Conectat la LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Conectat la LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Conectat la profilul pentru conținut media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Conectat la componenta audio a telefonului"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Conectat la serverul de transfer de fișiere"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permiteți redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Activați ferestrele cu formă liberă"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activați compatibilitatea pentru ferestrele experimentale cu formă liberă."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Modul desktop"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Parolă backup computer"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"În prezent, backupurile complete pe computer nu sunt protejate"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Atingeți ca să modificați sau să eliminați parola pentru backupurile complete pe desktop"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> până la finalizare"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> până la finalizare"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Încărcare limitată temporar"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Necunoscut"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Se încarcă"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Se încarcă rapid"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Se încarcă lent"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Se încarcă wireless"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Suport de încărcare"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nu se încarcă"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectat, nu se încarcă"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Încărcată"</string>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
index b1211a5..4b6e692 100644
--- a/packages/SettingsLib/res/values-ru/arrays.xml
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Выбор системы (по умолчанию)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Аудиокодек: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Аудиокодек: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Выбор системы (по умолчанию)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Аудиокодек: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Аудиокодек: <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Выбор системы (по умолчанию)"</item>
<item msgid="8003118270854840095">"44,1 кГц"</item>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 2b6250b..c27b55e 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD Audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD Audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Слуховые аппараты"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Слуховой аппарат подключен"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Подключено к LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Подключено к LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Подключено к мультимедийному аудиоустройству"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Подключено к аудиоустройству телефона"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Установлено подключение к серверу передачи файлов"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Разрешить изменение размера окон в многооконном режиме (независимо от значений в манифесте)"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Разрешить создание окон произвольной формы"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Включить экспериментальную функцию создания окон произвольной формы"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Режим компьютера"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Пароль для резервного копирования"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Полные локальные резервные копии в настоящее время не защищены"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Нажмите, чтобы изменить или удалить пароль для резервного копирования"</string>
@@ -448,7 +449,7 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (красный/зеленый)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (синий/желтый)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Коррекция цвета"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Коррекция цвета поможет вам:<br/> <ol> <li>&nbsp;Добиться нужной цветопередачи.</li> <li>&nbsp;Включить черно-белый режим, чтобы меньше отвлекаться.</li> </ol>"</string>
+ <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Используйте коррекцию цвета, чтобы:<br/> <ol> <li> Добиться нужной цветопередачи.</li> <li> Убрать цвета, которые мешают сосредоточиться.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"Уровень заряда – <xliff:g id="PERCENTAGE">%1$s</xliff:g>. <xliff:g id="TIME_STRING">%2$s</xliff:g>."</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до полной зарядки"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядка временно ограничена"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Идет зарядка"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Быстрая зарядка"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Медленная зарядка"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Беспроводная зарядка"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Док-станция: зарядка"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не заряжается"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Подключено, не заряжается"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Батарея заряжена"</string>
@@ -586,7 +589,7 @@
<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="creating_new_user_dialog_message" msgid="7232880257538970375">"Создаем нового пользователя…"</string>
- <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Создание гостя…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Создание профиля…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"Не удалось создать пользователя"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"Не удалось создать гостя."</string>
<string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Качество воздуха"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Данные о трансляции"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Автоматизация дома"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"SmartSpace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Выберите фото профиля"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Значок пользователя по умолчанию"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Физическая клавиатура"</string>
diff --git a/packages/SettingsLib/res/values-si/arrays.xml b/packages/SettingsLib/res/values-si/arrays.xml
index 8386c1a..eaacfb8 100644
--- a/packages/SettingsLib/res/values-si/arrays.xml
+++ b/packages/SettingsLib/res/values-si/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ශ්රව්යය"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ශ්රව්යය"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ශ්රව්යය"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ශ්රව්යය"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
<item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 9318c8d..dfc7bf9 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ශ්රව්යය: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ශ්රව්යය"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"ශ්රවණාධාරක"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE ශ්රව්ය"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"ශ්රවණාධාරක වෙත සම්බන්ධ කළා"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO වෙත සම්බන්ධ විය"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ශ්රව්ය වෙත සම්බන්ධ විය"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"මාධ්ය ශ්රව්යට සම්බන්ධ විය"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"දුරකතනයේ ශ්රව්යට සම්බන්ධ විය"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ගොනු හුවමාරු සේවාදායකය සමග සම්බන්ධ විය"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්රියාකාරකම් බහු-කවුළුව සඳහා ප්රතිප්රමාණ කළ හැකි බවට පත් කරන්න."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"අනියම් හැඩැති කවුළු සබල කරන්න"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"පරීක්ෂණාත්මක අනියම් හැඩැති කවුළු සඳහා සහාය සබල කරන්න."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"ඩෙස්ක්ටොප් ප්රකාරය"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ඩෙස්ක්ටොප් උපස්ථ මුරපදය"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ දැනට ආරක්ෂා කර නොමැත"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ සඳහා මුරපදය වෙනස් කිරීමට හෝ ඉවත් කිරීමට තට්ටු කරන්න"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"සම්පූර්ණ වීමට <xliff:g id="TIME">%1$s</xliff:g>ක් ඉතිරියි"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - සම්පූර්ණ වීමට <xliff:g id="TIME">%2$s</xliff:g>ක් ඉතිරියි"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණය කිරීම තාවකාලිකව සීමා කර ඇත"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"නොදනී"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ආරෝපණය වෙමින්"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ශීඝ්ර ආරෝපණය"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"සෙමින් ආරෝපණය"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"නොරැහැන්ව ආරෝපණය වේ"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ආරෝපණ ඩොකය"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ආරෝපණය නොවේ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"සම්බන්ධයි, ආරෝපණය නොවේ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"අරෝපිතයි"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"වායු ගුණත්වය"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"විකාශ තතු"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"නිවෙස් පාලන"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"ස්මාර්ට් අවකාශය"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"පැතිකඩ පින්තූරයක් තේරීම"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"පෙරනිමි පරිශීලක නිරූපකය"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"භෞතික යතුරු පුවරුව"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 6dee1e3..8f435fb 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD zvuk"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Načúvadlá"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Pripojené k načúvadlám"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Pripojené k profilu LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Pripojené k systému LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Pripojené ku zvukovému médiu"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Pripojené ku zvuku telefónu"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Pripojené na server pre prenos údajov"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Umožniť zmeniť veľkosť všetkých aktivít na niekoľko okien (bez ohľadu na hodnoty manifestu)"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Povoliť okná s voľným tvarom"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Povoliť podporu pre experimentálne okná s voľným tvarom"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Režim počítača"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Heslo pre zálohy v počítači"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Úplné zálohy v počítači nie sú momentálne chránené"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Klepnutím zmeníte alebo odstránite heslo pre úplné zálohy do počítača"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do úplného nabitia"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – nabíjanie je dočasne obmedzené"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznáme"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíja sa"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rýchle nabíjanie"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Pomalé nabíjanie"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Nabíja sa bezdrôtovo"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Nabíjací dok"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenabíja sa"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Pripojené, nenabíja sa"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Nabité"</string>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index 6e33e38..b2003e5 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Uporabi sistemsko izbiro (privzeto)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Uporabi sistemsko izbiro (privzeto)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Uporabi sistemsko izbiro (privzeto)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index c35ee7a..b3a29063 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Zvok visoke kakovosti: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Zvok visoke kakovosti"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Slušni pripomočki"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Povezava s slušnimi pripomočki je vzpostavljena"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Povezano s profilom LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Povezano s profilom LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Povezan s profilom za predstavnostni zvok"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Povezava s profilom za zvok telefona vzpostavljena"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Povezava s strežnikom za prenos datotek je vzpostavljena"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsem aktivnostim spremeniti velikost za način z več okni."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Omogoči okna svobodne oblike"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogoči podporo za poskusna okna svobodne oblike."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Namizni način"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Geslo za varnostno kopijo namizja"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Popolne varnostne kopije namizja trenutno niso zaščitene."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dotaknite se, če želite spremeniti ali odstraniti geslo za popolno varnostno kopiranje namizja"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Še <xliff:g id="TIME">%1$s</xliff:g> do napolnjenosti"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – še <xliff:g id="TIME">%2$s</xliff:g> do napolnjenosti"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Začasno omejeno polnjenje"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznano"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Polnjenje"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hitro polnjenje"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Počasno polnjenje"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Brezžično polnjenje"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Polnjenje na nosilcu"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Se ne polni"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Povezano, se ne polni"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Napolnjeno"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Kakovost zraka"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"O zasedbi"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Nadzor doma"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Hitri pregled"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Izbira profilne slike"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Privzeta ikona uporabnika"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Fizična tipkovnica"</string>
diff --git a/packages/SettingsLib/res/values-sq/arrays.xml b/packages/SettingsLib/res/values-sq/arrays.xml
index 8a6d853..ed86380 100644
--- a/packages/SettingsLib/res/values-sq/arrays.xml
+++ b/packages/SettingsLib/res/values-sq/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Përdor përzgjedhjen e sistemit (e parazgjedhur)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Audioja e <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Audioja e <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Përdor përzgjedhjen e sistemit (e parazgjedhur)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Audioja e <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Audioja e <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Përdor përzgjedhjen e sistemit (e parazgjedhur)"</item>
<item msgid="8003118270854840095">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index a92ef7c..83d95a3 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Aparatet e dëgjimit"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Audioja LE"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Lidhur me aparatet e dëgjimit"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Lidhur me LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"U lidh me audion LE"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"U lidh me audion e medias"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"U lidh me audion e telefonit"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"U lidh me serverin e transferimit të skedarëve"</string>
@@ -183,8 +183,8 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"Përdoruesi: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Disa caktime me parazgjedhje"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"Nuk janë caktuar parazgjedhje"</string>
- <string name="tts_settings" msgid="8130616705989351312">"Cilësimet \"tekst-në-ligjërim\""</string>
- <string name="tts_settings_title" msgid="7602210956640483039">"Dalja \"tekst-në-ligjërim\""</string>
+ <string name="tts_settings" msgid="8130616705989351312">"Cilësimet \"Tekst në ligjërim\""</string>
+ <string name="tts_settings_title" msgid="7602210956640483039">"Dalja \"Tekst në ligjërim\""</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Shpejtësia e të folurit"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"Shpejtësia me të cilën thuhet teksti"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"Tonaliteti"</string>
@@ -198,7 +198,7 @@
<string name="tts_install_data_title" msgid="1829942496472751703">"Instalo të dhënat e zërit"</string>
<string name="tts_install_data_summary" msgid="3608874324992243851">"Instalo të dhënat e zërit që kërkohen për sintezën e të folurit"</string>
<string name="tts_engine_security_warning" msgid="3372432853837988146">"Ky motor i sintezës së të folurit mund të mbledhë të gjithë tekstin që do të flitet, duke përfshirë të dhëna personale si fjalëkalime dhe numra kartash krediti. Ai vjen nga motori <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Të aktivizohet përdorimi i këtij motori të sintezës së të folurit?"</string>
- <string name="tts_engine_network_required" msgid="8722087649733906851">"Kjo gjuhë kërkon një lidhje funksionale interneti për daljen \"tekst-në-ligjërim\"."</string>
+ <string name="tts_engine_network_required" msgid="8722087649733906851">"Kjo gjuhë kërkon një lidhje funksionale interneti për daljen \"Tekst në ligjërim\"."</string>
<string name="tts_default_sample_string" msgid="6388016028292967973">"Ky është një shembull i sintezës së të folurit"</string>
<string name="tts_status_title" msgid="8190784181389278640">"Statusi i gjuhës së parazgjedhur"</string>
<string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> mbështetet plotësisht"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Bëj që të gjitha aktivitetet të kenë madhësi të ndryshueshme për përdorimin me shumë dritare, pavarësisht vlerave të manifestit."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Aktivizo dritaret me formë të lirë"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivizo mbështetjen për dritaret eksperimentale me formë të lirë."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Modaliteti i desktopit"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Fjalëkalimi rezervë i kompjuterit"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Rezervimet e plota në kompjuter nuk janë të mbrojtura aktualisht"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Trokit për të ndryshuar ose hequr fjalëkalimin për rezervime të plota të desktopit"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> derisa të mbushet"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> derisa të mbushet"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Karikimi përkohësisht i kufizuar"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"I panjohur"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Po karikohet"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Karikim i shpejtë"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Po karikohet ngadalë"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Po karikohet pa tel"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Në stacion karikimi"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nuk po karikohet"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Lidhur, jo në karikim"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Karikuar"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Cilësia e ajrit"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Të dhënat e aktorëve"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Kontrollet e shtëpisë"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Zgjidh një fotografi profili"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Ikona e parazgjedhur e përdoruesit"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Tastiera fizike"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index dee7f9d..ea370f6 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD звук: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD звук"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Слушни апарати"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Повезано са слушним апаратима"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Повезано са LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Повезано са LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Повезано са звуком медија"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Повезано са звуком телефона"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Повезано са сервером за пренос датотека"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Омогућава промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Омогући прозоре произвољног формата"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Омогућава подршку за експерименталне прозоре произвољног формата."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Режим за рачунаре"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Лозинка резервне копије за рачунар"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Резервне копије читавог система тренутно нису заштићене"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Додирните да бисте променили или уклонили лозинку за прављење резервних копија читавог система на рачунару"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до краја пуњења"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до краја пуњења"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Пуњење је привремено ограничено"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Пуни се"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо се пуни"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Споро се пуни"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бежично пуњење"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Станица за пуњење"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не пуни се"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Повезано, не пуни се"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Напуњено"</string>
@@ -601,7 +604,7 @@
<string name="guest_resetting" msgid="7822120170191509566">"Сесија госта се ресетује…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Желите да ресетујете сесију госта?"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Тиме ћете покренути нову сесију госта и избрисати све апликације и податке из актуелне сесије"</string>
- <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Изаћи ћете из режима госта?"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Излазите из режима госта?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Тиме ћете избрисати све апликације и податке из актуелне сесије госта"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Изађи"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Сачуваћете активности госта?"</string>
@@ -610,7 +613,7 @@
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Сачувај"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"Изађи из режима госта"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"Ресетуј сесију госта"</string>
- <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Изађи из режима госта"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Затвори режим госта"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Све активности ће бити избрисане при излазу"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Можете да сачувате или избришете активности при излазу"</string>
<string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Ресетујете за брисање активности сесије, или сачувајте или избришите активности при излазу"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 09b3d7a..970f549 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-ljud: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-ljud"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Hörapparater"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Ansluten till hörapparater"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Ansluten till LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Ansluten till LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ansluten till medialjud"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ansluten till telefonens ljud"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Ansluten till filöverföringsserver"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gör det möjligt att ändra storleken på alla aktiviteter i flerfönsterläge, oavsett manifestvärden."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Aktivera frihandsfönster"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivera stöd för experimentella frihandsfönster."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Datorläge"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Lösenord för säkerhetskopia av datorn"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"De fullständiga säkerhetskopiorna av datorn är för närvarande inte skyddade"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tryck om du vill ändra eller ta bort lösenordet för fullständig säkerhetskopiering av datorn"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> kvar tills fulladdat"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kvar tills fulladdat"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – laddning har begränsats tillfälligt"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Okänd"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laddar"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laddas snabbt"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Laddas långsamt"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Laddas trådlöst"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Dockningsstation"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Laddar inte"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ansluten, laddas inte"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Laddat"</string>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index dab4279..53dc6e5 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"ramani ya 13"</item>
<item msgid="8147982633566548515">"ramani ya 14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Tumia Uteuzi wa Mfumo (Chaguomsingi)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Sauti ya <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Sauti ya <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Tumia Uteuzi wa Mfumo (Chaguomsingi)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Sauti ya <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Sauti ya <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Tumia Uteuzi wa Mfumo (Chaguomsingi)"</item>
<item msgid="8003118270854840095">"kHz 44.1"</item>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 63a732d..476daf9 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Sauti ya HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Sauti ya HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Vifaa vya Kusaidia Kusikia"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Imeunganishwa kwenye Vifaa vya Kusaidia Kusikia"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Imeunganishwa kwenye LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Imeunganishwa kwenye LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Imeunganishwa kwenye sikika ya njia ya mawasiliano"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Imeunganishwa kwenye sauti ya simu"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Imeunganishwa kwenye seva ya kuhamisha faili"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwenye madirisha mengi, bila kuzingatia thamani za faili ya maelezo."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Washa madirisha yenye muundo huru"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ruhusu uwezo wa kutumia madirisha ya majaribio yenye muundo huru."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Hali ya kompyuta ya mezani"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Nenosiri la hifadhi rudufu ya eneo kazi"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Hifadhi rudufu kamili za eneo kazi hazijalindwa kwa sasa"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Gusa ili ubadilishe au uondoe nenosiri la hifadhi rudufu kamili za eneo kazi"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Zimesalia <xliff:g id="TIME">%1$s</xliff:g> ijae chaji"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> zimesalia ijae chaji"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kuchaji kumedhibitiwa kwa muda"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Haijulikani"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Inachaji"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Inachaji kwa kasi"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Inachaji pole pole"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Inachaji bila kutumia waya"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Kituo cha Kuchaji"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Haichaji"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Imeunganishwa, haichaji"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Imechajiwa"</string>
@@ -596,11 +599,11 @@
<string name="guest_reset_guest" msgid="6110013010356013758">"Badilisha kipindi cha mgeni"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Ungependa kubadilisha kipindi cha mgeni?"</string>
<string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Ungependa kumwondoa mgeni?"</string>
- <string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Badilisha"</string>
+ <string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Weka upya"</string>
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Ondoa"</string>
<string name="guest_resetting" msgid="7822120170191509566">"Inabadilisha kipindi cha mgeni…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Ungependa kuweka upya kipindi cha mgeni?"</string>
- <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Hii itaanzisha upya kipindi cha mgeni na kufuta programu na data yote kwenye kipindi cha sasa"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Hatua hii itaanzisha upya kipindi cha mgeni na kufuta programu na data yote kwenye kipindi cha sasa"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"Utafunga matumizi ya wageni?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"Hatua hii itafuta programu na data kutoka kwenye kipindi cha mgeni cha sasa"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"Funga"</string>
@@ -610,7 +613,7 @@
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"Hifadhi"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"Funga matumizi ya wageni"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"Weka upya kipindi cha mgeni"</string>
- <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Funga utumiaji wa mgeni"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Funga wasifu wa mgeni"</string>
<string name="guest_notification_ephemeral" msgid="7263252466950923871">"Shughuli zote zitafutwa wakati wa kufunga"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Unaweza kuhifadhi au kufuta shughuli zako wakati wa kufunga"</string>
<string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Weka upya ili ufute shughuli za kipindi sasa au unaweza kuhifadhi au kufuta shughuli wakati wa kufunga"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Ubora wa Hewa"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Maelezo ya Wahusika"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Udhibiti wa Vifaa Nyumbani"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Chagua picha ya wasifu"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Aikoni chaguomsingi ya mtumiaji"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Kibodi halisi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 1f71788..962ec34 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ஆடியோ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ஆடியோ"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"செவித்துணை கருவிகள்"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE ஆடியோ"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"செவித்துணை கருவிகளுடன் இணைக்கப்பட்டது"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO உடன் இணைக்கப்பட்டது"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ஆடியோவுடன் இணைக்கப்பட்டுள்ளது"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"மீடியா ஆடியோவுடன் இணைக்கப்பட்டது"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"மொபைல் ஆடியோவுடன் இணைக்கப்பட்டது"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ஃபைலைப் பரிமாற்றும் சேவையகத்துடன் இணைக்கப்பட்டது"</string>
@@ -408,6 +408,8 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமை."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"குறிப்பிட்ட வடிவமில்லாத சாளரங்களை இயக்கு"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"சாளரங்களை அளவுமாற்ற மற்றும் எங்கும் நகர்த்த அனுமதிக்கும் பரிசோதனைக்குரிய அம்சத்திற்கான ஆதரவை இயக்கு."</string>
+ <!-- no translation found for desktop_mode (2389067840550544462) -->
+ <skip />
<string name="local_backup_password_title" msgid="4631017948933578709">"டெஸ்க்டாப் காப்புப்பிரதி கடவுச்சொல்"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"டெஸ்க்டாப்பின் முழு காப்புப்பிரதிகள் தற்போது பாதுகாக்கப்படவில்லை"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"டெஸ்க்டாப்பின் முழுக் காப்புப் பிரதிகளுக்கான கடவுச்சொல்லை மாற்ற அல்லது அகற்ற, தட்டவும்"</string>
@@ -476,13 +478,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"முழுவதும் சார்ஜாக <xliff:g id="TIME">%1$s</xliff:g> ஆகும்"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - முழுவதும் சார்ஜாக <xliff:g id="TIME">%2$s</xliff:g> ஆகும்"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - சார்ஜாவது தற்காலிகமாக வரம்பிடப்பட்டுள்ளது"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"அறியப்படாத"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"சார்ஜ் ஆகிறது"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"வேகமாக சார்ஜாகிறது"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"மெதுவாக சார்ஜாகிறது"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"வயரின்றி சார்ஜாகிறது"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"சார்ஜிங் டாக்"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"சார்ஜ் செய்யப்படவில்லை"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"இணைக்கப்பட்டுள்ளது, சார்ஜாகவில்லை"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"சார்ஜாகிவிட்டது"</string>
@@ -586,7 +590,7 @@
<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="creating_new_user_dialog_message" msgid="7232880257538970375">"புதிய பயனரை உருவாக்குகிறது…"</string>
- <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"புதிய விருந்தினரை உருவாக்குகிறது…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"புதிய கெஸ்ட் பயனரை உருவாக்குகிறது…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"புதிய பயனரை உருவாக்க முடியவில்லை"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"புதிய விருந்தினரை உருவாக்க முடியவில்லை"</string>
<string name="user_nickname" msgid="262624187455825083">"புனைப்பெயர்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 592810e..cc1f291 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -117,17 +117,17 @@
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"ఫైల్ బదిలీ"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"ఇన్పుట్ పరికరం"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"ఇంటర్నెట్ యాక్సెస్"</string>
- <string name="bluetooth_profile_pbap" msgid="4262303387989406171">"Contacts and call history sharing"</string>
- <string name="bluetooth_profile_pbap_summary" msgid="6466456791354759132">"Use for contacts and call history sharing"</string>
+ <string name="bluetooth_profile_pbap" msgid="4262303387989406171">"కాంటాక్ట్లు, కాల్ హిస్టరీ షేరింగ్"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="6466456791354759132">"కాంటాక్ట్లు, కాల్ హిస్టరీ షేరింగ్ కోసం ఉపయోగించండి"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ఇంటర్నెట్ కనెక్షన్ షేరింగ్"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"టెక్స్ట్ మెసేజ్లు"</string>
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM యాక్సెస్"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ఆడియో: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ఆడియో"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"వినికిడి మద్దతు ఉపకరణాలు"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Le ఆడియో"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"వినికిడి మద్దతు ఉపకరణాలకు కనెక్ట్ చేయబడింది"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIOకు కనెక్ట్ చేయబడింది"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE ఆడియోకు కనెక్ట్ చేయబడింది"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"మీడియా ఆడియోకు కనెక్ట్ చేయబడింది"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"ఫోన్ ఆడియోకు కనెక్ట్ చేయబడింది"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ఫైల్ బదిలీ సర్వర్కు కనెక్ట్ చేయబడింది"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా అన్ని యాక్టివిటీస్ను పలు రకాల విండోల్లో సరిపోయేటట్లు సైజ్ మార్చగలిగేలా చేస్తుంది."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"స్వతంత్ర రూప విండోలను ఎనేబుల్ చేయండి"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"ప్రయోగాత్మక స్వతంత్ర రూప విండోల కోసం సపోర్ట్ను ఎనేబుల్ చేస్తుంది."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"డెస్క్టాప్ మోడ్"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"డెస్క్టాప్ బ్యాకప్ పాస్వర్డ్"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"డెస్క్టాప్ పూర్తి బ్యాకప్లు ప్రస్తుతం రక్షించబడలేదు"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"డెస్క్టాప్ పూర్తి బ్యాకప్ల కోసం పాస్వర్డ్ను మార్చడానికి లేదా తీసివేయడానికి నొక్కండి"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జింగ్ తాత్కాలికంగా పరిమితం చేయబడింది"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"తెలియదు"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ఛార్జ్ అవుతోంది"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"వేగవంతమైన ఛార్జింగ్"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"నెమ్మదిగా ఛార్జింగ్"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"వైర్లెస్ ఛార్జింగ్"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"ఛార్జింగ్ డాక్"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ఛార్జ్ కావడం లేదు"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"కనెక్ట్ చేయబడింది, ఛార్జ్ చేయబడలేదు"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ఛార్జ్ చేయబడింది"</string>
@@ -586,7 +589,7 @@
<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="creating_new_user_dialog_message" msgid="7232880257538970375">"కొత్త యూజర్ను క్రియేట్ చేస్తోంది…"</string>
- <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"కొత్త అతిథిని క్రియేట్ చేస్తోంది…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"కొత్త గెస్ట్ను క్రియేట్ చేస్తోంది…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"కొత్త యూజర్ను క్రియేట్ చేయడం విఫలమైంది"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"కొత్త అతిథిని క్రియేట్ చేయడం విఫలమైంది"</string>
<string name="user_nickname" msgid="262624187455825083">"మారుపేరు"</string>
@@ -601,17 +604,17 @@
<string name="guest_resetting" msgid="7822120170191509566">"గెస్ట్ సెషన్ను రీసెట్ చేస్తోంది…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"గెస్ట్ సెషన్ను రీసెట్ చేయాలా?"</string>
<string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"ఇది కొత్త గెస్ట్ సెషన్ను ప్రారంభిస్తుంది, ప్రస్తుత సెషన్ నుండి అన్ని యాప్లు, డేటాను తొలగిస్తుంది."</string>
- <string name="guest_exit_dialog_title" msgid="1846494656849381804">"గెస్ట్ మోడ్ నిష్క్రమించాలా?"</string>
+ <string name="guest_exit_dialog_title" msgid="1846494656849381804">"గెస్ట్ మోడ్ నుండి వైదొలగాలా?"</string>
<string name="guest_exit_dialog_message" msgid="1743218864242719783">"ఇది ప్రస్తుత గెస్ట్ సెషన్ నుండి యాప్లను వాటితో పాటు డేటాను తొలగిస్తుంది"</string>
- <string name="guest_exit_dialog_button" msgid="1736401897067442044">"నిష్క్రమించండి"</string>
+ <string name="guest_exit_dialog_button" msgid="1736401897067442044">"వైదొలగండి"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"గెస్ట్ యాక్టివిటీని సేవ్ చేయాలా?"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"మీరు సెషన్ నుండి యాక్టివిటీని సేవ్ చేయవచ్చు, అన్ని యాప్లు, డేటాను తొలగించవచ్చు"</string>
<string name="guest_exit_clear_data_button" msgid="3425812652180679014">"తొలగించండి"</string>
<string name="guest_exit_save_data_button" msgid="3690974510644963547">"సేవ్ చేయండి"</string>
<string name="guest_exit_button" msgid="5774985819191803960">"గెస్ట్ మోడ్ నుండి వైదొలగండి"</string>
<string name="guest_reset_button" msgid="2515069346223503479">"గెస్ట్ సెషన్ను రీసెట్ చేయండి"</string>
- <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"గెస్ట్ మోడ్ నుండి నిష్క్రమించండి"</string>
- <string name="guest_notification_ephemeral" msgid="7263252466950923871">"నిష్క్రమణ సమయంలో మొత్తం యాక్టివిటీ తొలగించబడుతుంది"</string>
+ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"గెస్ట్ మోడ్ నుండి వైదొలగండి"</string>
+ <string name="guest_notification_ephemeral" msgid="7263252466950923871">"వైదొలగినప్పుడు యాక్టివిటీ అంతా తొలగించబడుతుంది"</string>
<string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"మీ నిష్క్రమణలో, యాక్టివిటీని సేవ్ చేయవచ్చు లేదా తొలగించవచ్చు"</string>
<string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"సెషన్ యాక్టివిటీని తొలగించడానికి ఇప్పుడే రీసెట్ చేయండి లేదా మీరు నిష్క్రమించేటప్పుడు యాక్టివిటీని సేవ్ చేయవచ్చు లేదా తొలగించవచ్చు"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ఒక ఫోటో తీయండి"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index aa01af7..65744b2 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"เสียง HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"เสียง HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"เครื่องช่วยฟัง"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"เชื่อมต่อกับเครื่องช่วยฟังแล้ว"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"เชื่อมต่อกับ LE_AUDIO แล้ว"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"เชื่อมต่อกับ LE Audio แล้ว"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"เชื่อมต่อกับระบบเสียงของสื่อแล้ว"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"เชื่อมต่อกับระบบเสียงของโทรศัพท์แล้ว"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"เชื่อมต่อกับเซิร์ฟเวอร์สำหรับโอนไฟล์แล้ว"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"เปิดใช้หน้าต่างรูปแบบอิสระ"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"เปิดการสนับสนุนหน้าต่างรูปแบบอิสระแบบทดลอง"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"โหมดเดสก์ท็อป"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"รหัสผ่านการสำรองข้อมูลในเดสก์ท็อป"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"การสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อปไม่ได้รับการป้องกันในขณะนี้"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"แตะเพื่อเปลี่ยนแปลงหรือลบรหัสผ่านสำหรับการสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"อีก <xliff:g id="TIME">%1$s</xliff:g>จึงจะเต็ม"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - อีก <xliff:g id="TIME">%2$s</xliff:g> จึงจะเต็ม"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - จำกัดการชาร์จชั่วคราว"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"ไม่ทราบ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"กำลังชาร์จ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"กำลังชาร์จอย่างเร็ว"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"กำลังชาร์จอย่างช้าๆ"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"กำลังชาร์จแบบไร้สาย"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"กำลังชาร์จบนแท่น"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ไม่ได้ชาร์จ"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"เชื่อมต่ออยู่ ไม่ได้ชาร์จ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ชาร์จแล้ว"</string>
@@ -586,7 +589,7 @@
<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="creating_new_user_dialog_message" msgid="7232880257538970375">"กำลังสร้างผู้ใช้ใหม่…"</string>
- <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"กำลังสร้างผู้เข้าร่วมใหม่…"</string>
+ <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"กำลังสร้างผู้ใช้ชั่วคราวใหม่…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"สร้างผู้ใช้ใหม่ไม่ได้"</string>
<string name="add_guest_failed" msgid="8074548434469843443">"สร้างผู้เข้าร่วมใหม่ไม่สำเร็จ"</string>
<string name="user_nickname" msgid="262624187455825083">"ชื่อเล่น"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index c2f2035..6b1411d 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Mga Hearing Aid"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Nakakonekta sa Mga Hearing Aid"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Nakakonekta sa LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Nakakonekta sa LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Konektado sa media audio"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Nakakonekta sa audio ng telepono"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Nakakonekta sa server sa paglilipat ng file"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gawing nare-resize ang lahat ng aktibidad para sa multi-window, anuman ang mga value ng manifest."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"I-enable ang mga freeform window"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"I-enable ang suporta para sa mga pang-eksperimentong freeform window."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Desktop mode"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Password ng pag-backup ng desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Kasalukuyang hindi pinoprotektahan ang mga buong pag-backup ng desktop"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"I-tap upang baguhin o alisin ang password para sa mga kumpletong pag-back up sa desktop"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> na lang bago mapuno"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> na lang bago mapuno"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pansamantalang limitado ang pag-charge"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Hindi Kilala"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nagcha-charge"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mabilis na charge"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Mabagal na charge"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Wireless na nagcha-charge"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Charging Dock"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Hindi nagcha-charge"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Nakakonekta, hindi nagcha-charge"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Nasingil"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 0bc9cc2..af51c68 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ses: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ses"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"İşitme Cihazları"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"İşitme Cihazlarına Bağlandı"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO\'ya bağlandı"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE Audio\'ya bağlandı"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Medya sesine bağlanıldı"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefon sesine bağlandı"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Dosya aktarım sunucusuna bağlandı"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir yap."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Serbest biçimli pencereleri etkinleştir"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Deneysel serbest biçimli pencere desteğini etkinleştir."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Masaüstü modu"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Masaüstü yedekleme şifresi"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Masaüstü tam yedeklemeleri şu an korunmuyor"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Masaüstü tam yedeklemelerinin şifresini değiştirmek veya kaldırmak için dokunun"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Tamamen şarj olmasına <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
<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="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj etme geçici olarak sınırlı"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Bilinmiyor"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Şarj oluyor"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hızlı şarj oluyor"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Yavaş şarj oluyor"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Kablosuz şarj oluyor"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Şarj Yuvası"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Şarj olmuyor"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Bağlandı, şarj olmuyor"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Şarj oldu"</string>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
index 0410bd6..c32da85 100644
--- a/packages/SettingsLib/res/values-uk/arrays.xml
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Використовувати вибір системи (за умовчанням)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"Аудіо <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2908219194098827570">"Аудіо <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Використовувати вибір системи (за умовчанням)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"Аудіо <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="3517061573669307965">"Аудіо <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Використовувати вибір системи (за умовчанням)"</item>
<item msgid="8003118270854840095">"44,1 кГц"</item>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 03e3ef9..8e102e4 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -117,7 +117,7 @@
<string name="bluetooth_profile_opp" msgid="6692618568149493430">"Передавання файлів"</string>
<string name="bluetooth_profile_hid" msgid="2969922922664315866">"Пристрій введення"</string>
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"Доступ до Інтернету"</string>
- <string name="bluetooth_profile_pbap" msgid="4262303387989406171">"Надсилання контактів та історії викликів"</string>
+ <string name="bluetooth_profile_pbap" msgid="4262303387989406171">"Доступ до контактів та історії дзвінків"</string>
<string name="bluetooth_profile_pbap_summary" msgid="6466456791354759132">"Використовуйте, щоб надсилати контакти й історію викликів"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Надання доступу до Інтернету"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"Текстові повідомлення"</string>
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD-аудіо: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD-аудіо"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Слухові апарати"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Підключено до слухових апаратів"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Підключено до LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Підключено до LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Підключено до аудіоджерела"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Підключено до звуку телеф."</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Підключ. до сервера передачі файлів"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Масштабувати активність на кілька вікон, незалежно від значень у файлі маніфесту."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Увімкнути вікна довільного формату"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Увімкнути експериментальні вікна довільного формату."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Режим комп’ютера"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Пароль рез. копії на ПК"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Повні резервні копії на комп’ютері наразі не захищені"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Торкніться, щоб змінити або видалити пароль для повного резервного копіювання на комп’ютер"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до повного заряду"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного заряду"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> • Заряджання тимчасово обмежено"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Невідомо"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Заряджається"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Швидке заряджання"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Повільне заряджання"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бездротове заряджання"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Зарядка: док-станція"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не заряджається"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Підключено, не заряджається"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Заряджено"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Якість повітря"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Акторський склад"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Автоматизація дому"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Виберіть зображення профілю"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Значок користувача за умовчанням"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Фізична клавіатура"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index cac1b6c..9e22b90 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD آڈیو: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD آڈیو"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"سماعتی آلات"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE آڈیو"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"سماعتی آلات سے منسلک ہے"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"LE_AUDIO سے منسلک ہے"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE آڈیو سے منسلک ہے"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"میڈیا آڈیو سے مربوط"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"فون آڈیو سے مربوط"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"فائل منتقلی سرور سے مربوط ہو گیا ہے"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"مینی فیسٹ اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بنائیں۔"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"freeform ونڈوز فعال کریں"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"تجرباتی فری فارم ونڈوز کیلئے سپورٹ فعال کریں۔"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"ڈیسک ٹاپ موڈ"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"ڈیسک ٹاپ کا بیک اپ پاس ورڈ"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"ڈیسک ٹاپ کے مکمل بیک اپس فی الحال محفوظ کیے ہوئے نہیں ہیں"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"ڈیسک ٹاپ کے مکمل بیک اپس کیلئے پاس ورڈ کو تبدیل کرنے یا ہٹانے کیلئے تھپتھپائیں"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"مکمل چارج ہونے میں <xliff:g id="TIME">%1$s</xliff:g> باقی ہے"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"مکمل چارج ہونے میں <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> باقی ہے"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> • چارجنگ عارضی طور پر محدود ہے"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"نامعلوم"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"چارج ہو رہا ہے"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"تیزی سے چارج ہو رہا ہے"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"آہستہ چارج ہو رہی ہے"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"وائرلیس طریقے سے چارج ہو رہی ہے"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"چارجنگ ڈاک"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"چارج نہیں ہو رہا ہے"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"منسلک ہے، چارج نہیں ہو رہی ہے"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"چارج ہو گئی"</string>
diff --git a/packages/SettingsLib/res/values-uz/arrays.xml b/packages/SettingsLib/res/values-uz/arrays.xml
index 7d09027..edbd180 100644
--- a/packages/SettingsLib/res/values-uz/arrays.xml
+++ b/packages/SettingsLib/res/values-uz/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"Tizim tanlovi (birlamchi)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audiokodeki"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audiokodeki"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"Tizim tanlovi (birlamchi)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audiokodeki"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audiokodeki"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Tizim tanlovi (birlamchi)"</item>
<item msgid="8003118270854840095">"44.1 kGs"</item>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index cae3814..c66b6cf 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD audio: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD audio"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Eshitish apparatlari"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Eshitish apparatlariga ulangan"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Ulandi: LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE audioga ulandi"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Audio qurilmasiga ulangan"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Telefon karnayiga ulanildi"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Fayl almashinish serveriga ulanildi"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtirish."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Erkin shakldagi oynalarni yoqish"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Erkin shakldagi oynalar yaratish uchun mo‘ljallangan tajribaviy funksiyani yoqish."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Desktop rejimi"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Zaxira nusxa uchun parol"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Kompyuterdagi zaxira nusxalar hozirgi vaqtda himoyalanmagan"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ish stoli to‘liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Toʻlishiga <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – Toʻlishiga <xliff:g id="TIME">%2$s</xliff:g> qoldi"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Quvvatlash vaqtincha cheklangan"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Noma’lum"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Quvvat olmoqda"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Tezkor quvvat olmoqda"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Sekin quvvat olmoqda"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Simsiz quvvat olmoqda"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Quvvatlash doki"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Quvvat olmayapti"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ulangan, quvvat olmayapti"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Quvvat oldi"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"Havo sifati"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"Translatsiya axboroti"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"Uy boshqaruvi"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"Profil rasmini tanlash"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"Foydalanuvchining standart belgisi"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"Tashqi klaviatura"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 1995e705..ed78108 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Âm thanh HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Âm thanh HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Thiết bị trợ thính"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Âm thanh LE"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Đã kết nối với Thiết bị trợ thính"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Đã kết nối với LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Đã kết nối với âm thanh LE"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Đã kết nối với âm thanh nội dung nghe nhìn"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Đã kết nối với âm thanh điện thoại"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Đã kết nối với máy chủ chuyển tệp"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Cho phép thay đổi kích thước của tất cả các hoạt động cho nhiều cửa sổ, bất kể giá trị tệp kê khai là gì."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Bật cửa sổ dạng tự do"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Bật tính năng hỗ trợ cửa sổ dạng tự do thử nghiệm."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Chế độ máy tính"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Mật khẩu sao lưu vào máy tính"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Các bản sao lưu đầy đủ vào máy tính hiện không được bảo vệ"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Nhấn để thay đổi hoặc xóa mật khẩu dành cho các bản sao lưu đầy đủ vào máy tính"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> nữa là pin đầy"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> nữa là pin đầy"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> – Mức sạc tạm thời bị giới hạn"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Không xác định"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Đang sạc"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Đang sạc nhanh"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Đang sạc chậm"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Đang sạc không dây"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Đế sạc"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Hiện không sạc"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Đã kết nối nhưng chưa sạc"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Đã sạc"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 973d7d0..2a85d31 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -85,10 +85,26 @@
<item msgid="7073042887003102964">"map13"</item>
<item msgid="8147982633566548515">"map14"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:6 (328951785723550863) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:7 (506175145534048710) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:6 (3940992993241040716) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:7 (7940970833006181407) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="2494959071796102843">"使用系统选择(默认)"</item>
+ <item msgid="4055460186095649420">"SBC"</item>
+ <item msgid="720249083677397051">"AAC"</item>
+ <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> 音频"</item>
+ <item msgid="2908219194098827570">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> 音频"</item>
+ <item msgid="3825367753087348007">"LDAC"</item>
+ <item msgid="328951785723550863">"LC3"</item>
+ <item msgid="506175145534048710">"Opus"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="8868109554557331312">"使用系统选择(默认)"</item>
+ <item msgid="9024885861221697796">"SBC"</item>
+ <item msgid="4688890470703790013">"AAC"</item>
+ <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> 音频"</item>
+ <item msgid="3517061573669307965">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> 音频"</item>
+ <item msgid="2553206901068987657">"LDAC"</item>
+ <item msgid="3940992993241040716">"LC3"</item>
+ <item msgid="7940970833006181407">"Opus"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"使用系统选择(默认)"</item>
<item msgid="8003118270854840095">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index c478085..e1e50ae 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD 音频:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD 音频"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"助听器"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE 音频"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"已连接到助听器"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"已连接到 LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"已连接到 LE 音频"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"已连接到媒体音频"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"已连接到手机音频"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"已连接到文件传输服务器"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"将所有 Activity 设为可配合多窗口环境调整大小(忽略清单值)。"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"启用可自由调整的窗口"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"启用可自由调整的窗口这一实验性功能。"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"桌面模式"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"桌面备份密码"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"桌面完整备份当前未设置密码保护"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"点按即可更改或移除用于保护桌面完整备份的密码"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"还需<xliff:g id="TIME">%1$s</xliff:g>充满"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还需<xliff:g id="TIME">%2$s</xliff:g>充满"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充电暂时受限"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"正在充电"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"正在快速充电"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"正在慢速充电"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"正在无线充电"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"充电基座"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"未在充电"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"已连接,未充电"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"已充满电"</string>
@@ -661,8 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"空气质量"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"投放信息"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"家居控制"</string>
- <!-- no translation found for dream_complication_title_smartspace (4197829945636051120) -->
- <skip />
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"SmartSpace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"选择个人资料照片"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"默认用户图标"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"实体键盘"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index b4667a8..1a6648f 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"高清音訊:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"高清音訊"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"助聽器"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE Audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"已連接助聽器"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"已連接 LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"已連接 LE Audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"已連接媒體音頻裝置"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"已連接手機耳機"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"已連線至檔案傳輸伺服器"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"在任何資訊清單值下,允許系統配合多重視窗環境調整所有活動的尺寸。"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"啟用自由形態視窗"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"啟用實驗版自由形態視窗的支援功能。"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"電腦模式"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"桌面電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"桌面電腦的完整備份目前未受保護"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"輕按即可變更或移除桌面電腦完整備份的密碼"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>後充滿電"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充滿電"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電暫時受限"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"慢速充電中"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"無線充電中"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"充電插座"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"已連接,非充電中"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"已充滿電"</string>
@@ -661,7 +664,7 @@
<string name="dream_complication_title_aqi" msgid="4587552608957834110">"空氣質素"</string>
<string name="dream_complication_title_cast_info" msgid="4038776652841885084">"投放資料"</string>
<string name="dream_complication_title_home_controls" msgid="9153381632476738811">"智能家居"</string>
- <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"智慧空間"</string>
+ <string name="dream_complication_title_smartspace" msgid="4197829945636051120">"Smartspace"</string>
<string name="avatar_picker_title" msgid="8492884172713170652">"選擇個人檔案相片"</string>
<string name="default_user_icon_description" msgid="6554047177298972638">"預設使用者圖示"</string>
<string name="physical_keyboard_title" msgid="4811935435315835220">"實體鍵盤"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 8097022..991dcad 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD 高解析音訊:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD 高解析音訊"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"助聽器"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"LE audio"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"已連接到助聽器"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"已連上 LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"已連上 LE audio"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"連接至媒體音訊"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"連接至電話音訊"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"已連線到檔案傳輸伺服器"</string>
@@ -241,7 +241,7 @@
<string name="adb_wireless_settings" msgid="2295017847215680229">"無線偵錯"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"如要查看並使用可用的裝置,請開啟無線偵錯功能"</string>
<string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"使用 QR 圖碼配對裝置"</string>
- <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"使用 QR 圖碼掃描器配對新裝置"</string>
+ <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"使用 QR code 掃描器配對新裝置"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"使用配對碼配對裝置"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"使用六位數的配對碼配對新裝置"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"已配對的裝置"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"啟用自由形式視窗"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"啟用實驗版自由形式視窗的支援功能。"</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"電腦模式"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"目前尚未設定密碼來保護完整的備份檔案 (透過電腦備份的檔案)"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"輕觸即可變更或移除電腦完整備份的密碼"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>後充飽"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - 已暫時限制充電"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"慢速充電中"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"正在進行無線充電"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"充電座架"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"已連接,尚未充電"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"充電完成"</string>
@@ -600,9 +603,9 @@
<string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"移除"</string>
<string name="guest_resetting" msgid="7822120170191509566">"正在重設訪客…"</string>
<string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"要重設訪客工作階段嗎?"</string>
- <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"這麼做將開始新的訪客工作階段,並刪除目前工作階段中的所有應用程式和資料"</string>
+ <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"如果重設,系統會開始新的訪客工作階段,並刪除目前工作階段中的所有應用程式和資料"</string>
<string name="guest_exit_dialog_title" msgid="1846494656849381804">"要結束訪客模式嗎?"</string>
- <string name="guest_exit_dialog_message" msgid="1743218864242719783">"這麼做將刪除目前訪客工作階段中的所有應用程式和資料"</string>
+ <string name="guest_exit_dialog_message" msgid="1743218864242719783">"如果結束,系統會刪除目前訪客工作階段中的所有應用程式和資料"</string>
<string name="guest_exit_dialog_button" msgid="1736401897067442044">"結束"</string>
<string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"要儲存訪客活動嗎?"</string>
<string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"你可以儲存目前工作階段中的活動,也可以刪除所有應用程式和資料"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 2321ace..f1f736c7 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -125,9 +125,9 @@
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Umsindo we-HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Umsindo we-HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Izinsiza zokuzwa"</string>
- <string name="bluetooth_profile_le_audio" msgid="5158149987518342036">"I-LE_AUDIO"</string>
+ <string name="bluetooth_profile_le_audio" msgid="3237854988278539061">"Umsindo we-LE"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Kuxhumeke kwizinsiza zokuzwa"</string>
- <string name="bluetooth_le_audio_profile_summary_connected" msgid="3162538609379333442">"Kuxhunywe ku-LE_AUDIO"</string>
+ <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"Kuxhunywe kumsindo we-LE"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Ixhume emsindweni wemidiya"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Ixhunywe kumsindo wefoni"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Ixhunywe kwiseva yokudlulisa ifayela"</string>
@@ -408,6 +408,7 @@
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Yenza yonke imisebenzi ibe nosayizi abasha kumawindi amaningi, ngokunganaki amavelu e-manifest."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Nika amandla amawindi e-freeform"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Nika amandla usekelo lwe-windows yokuhlola kwe-freeform."</string>
+ <string name="desktop_mode" msgid="2389067840550544462">"Imodi yedeskithophu"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Iphasiwedi yokusekela ngokulondoloza ye-Desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Ukusekela ngokulondoloza okugcwele kwe-Desktop akuvikelekile okwamanje."</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Thepha ukushintsha noma ukususa iphasiwedi yokwenziwa kwezipele ngokugcwele kwideskithophu"</string>
@@ -476,13 +477,15 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> okusele kuze kugcwale"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> okusele kuze kugcwale"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ukushaja kukhawulelwe okwesikhashana"</string>
+ <!-- no translation found for power_charging_limited (6971664137170239141) -->
+ <skip />
<string name="battery_info_status_unknown" msgid="268625384868401114">"Akwaziwa"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Iyashaja"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ishaja ngokushesha"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Ishaja kancane"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Iyashaja ngaphandle kwentambo"</string>
- <string name="battery_info_status_charging_dock" msgid="3554147903321236585">"Idokhu yokushaja"</string>
+ <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
+ <skip />
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ayishaji"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ixhunyiwe, ayishaji"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Kushajiwe"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 11cb9c1..0e60caa 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1125,7 +1125,7 @@
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
<string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> left until full</string>
<!-- [CHAR_LIMIT=80] Label for battery level chart when charge been limited -->
- <string name="power_charging_limited"><xliff:g id="level">%1$s</xliff:g> - Charging temporarily limited</string>
+ <string name="power_charging_limited"><xliff:g id="level">%1$s</xliff:g> - Charging is paused</string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="battery_info_status_unknown">Unknown</string>
@@ -1138,7 +1138,7 @@
<!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging wirelessly. -->
<string name="battery_info_status_charging_wireless">Charging wirelessly</string>
<!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when the device is dock charging. -->
- <string name="battery_info_status_charging_dock">Charging Dock</string>
+ <string name="battery_info_status_charging_dock">Charging</string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="battery_info_status_discharging">Not charging</string>
<!-- Battery Info screen. Value for a status item. A state which device is connected with any charger(e.g. USB, Adapter or Wireless) but not charging yet. Used for diagnostic info screens, precise translation isn't needed -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index b9c4030..a822e18 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -600,6 +600,9 @@
* Returns the WifiInfo for the underlying WiFi network of the VCN network, returns null if the
* input NetworkCapabilities is not for a VCN network with underlying WiFi network.
*
+ * TODO(b/238425913): Move this method to be inside systemui not settingslib once we've migrated
+ * off of {@link WifiStatusTracker} and {@link NetworkControllerImpl}.
+ *
* @param networkCapabilities NetworkCapabilities of the network.
*/
@Nullable
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index d1f10a6..86d2eb8 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -182,6 +182,7 @@
Settings.Secure.PEOPLE_STRIP,
Settings.Secure.MEDIA_CONTROLS_RESUME,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 4aadf72..6a70230 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -277,6 +277,7 @@
VALIDATORS.put(Secure.PEOPLE_STRIP, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.MEDIA_CONTROLS_RESUME, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.MEDIA_CONTROLS_RECOMMENDATION, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.MEDIA_CONTROLS_LOCK_SCREEN, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
new InclusiveIntegerRangeValidator(
Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
diff --git a/packages/SoundPicker/res/values-sk/strings.xml b/packages/SoundPicker/res/values-sk/strings.xml
index e7d444c..8ff6d12 100644
--- a/packages/SoundPicker/res/values-sk/strings.xml
+++ b/packages/SoundPicker/res/values-sk/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="ringtone_default" msgid="798836092118824500">"Predvolený tón zvonenia"</string>
<string name="notification_sound_default" msgid="8133121186242636840">"Predvolený zvuk upozornení"</string>
- <string name="alarm_sound_default" msgid="4787646764557462649">"Predvolený zvuk budíkov"</string>
+ <string name="alarm_sound_default" msgid="4787646764557462649">"Predvolený zvuk budíka"</string>
<string name="add_ringtone_text" msgid="6642389991738337529">"Pridať tón zvonenia"</string>
<string name="add_alarm_text" msgid="3545497316166999225">"Pridať budík"</string>
<string name="add_notification_text" msgid="4431129543300614788">"Pridať upozornenie"</string>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6edf13a..78dea89 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -85,6 +85,7 @@
<uses-permission android:name="android.permission.CONTROL_VPN" />
<uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
<uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL"/>
+ <uses-permission android:name="android.permission.NETWORK_STACK"/>
<!-- Physical hardware -->
<uses-permission android:name="android.permission.MANAGE_USB" />
<uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
@@ -394,6 +395,11 @@
android:label="@string/screenshot_scroll_label"
android:finishOnTaskLaunch="true" />
+ <service android:name=".screenshot.ScreenshotProxyService"
+ android:permission="com.android.systemui.permission.SELF"
+ android:exported="false" />
+
+
<service android:name=".screenrecord.RecordingService" />
<receiver android:name=".SysuiRestartReceiver"
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 4b07eaf..fa855ab 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -20,6 +20,7 @@
dupin@google.com
ethibodeau@google.com
evanlaird@google.com
+florenceyang@google.com
gwasserman@google.com
hwwang@google.com
hyunyoungs@google.com
@@ -28,6 +29,8 @@
jbolinger@google.com
jdemeulenaere@google.com
jeffdq@google.com
+jernej@google.com
+jglazier@google.com
jjaggi@google.com
jonmiranda@google.com
joshtrask@google.com
@@ -49,8 +52,11 @@
nicomazz@google.com
ogunwale@google.com
peanutbutter@google.com
+peskal@google.com
pinyaoting@google.com
pixel@google.com
+pomini@google.com
+rahulbanerjee@google.com
roosa@google.com
santie@google.com
shanh@google.com
@@ -68,12 +74,10 @@
vadimt@google.com
victortulias@google.com
winsonc@google.com
-yurilin@google.com
xuqiu@google.com
+yuandizhou@google.com
+yurilin@google.com
zakcohen@google.com
-jernej@google.com
-jglazier@google.com
-peskal@google.com
#Android Auto
hseog@google.com
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 154a6fc..26feaf9 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -137,6 +137,22 @@
]
}
],
+ "ironwood-postsubmit": [
+ {
+ "name": "PlatformScenarioTests",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.IwTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.platform.test.scenario.sysui"
+ }
+ ]
+ }
+ ],
"auto-end-to-end-postsubmit": [
{
"name": "AndroidAutomotiveHomeTests",
diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp
index 40218de..325ede6 100644
--- a/packages/SystemUI/compose/features/Android.bp
+++ b/packages/SystemUI/compose/features/Android.bp
@@ -30,6 +30,7 @@
],
static_libs: [
+ "SystemUI-core",
"SystemUIComposeCore",
"androidx.compose.runtime_runtime",
diff --git a/packages/SystemUI/compose/features/AndroidManifest.xml b/packages/SystemUI/compose/features/AndroidManifest.xml
index 0aea99d..eada40e 100644
--- a/packages/SystemUI/compose/features/AndroidManifest.xml
+++ b/packages/SystemUI/compose/features/AndroidManifest.xml
@@ -16,7 +16,38 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+
package="com.android.systemui.compose.features">
-
-
+ <application
+ android:name="android.app.Application"
+ android:appComponentFactory="androidx.core.app.AppComponentFactory"
+ tools:replace="android:name,android:appComponentFactory">
+ <!-- Disable providers from SystemUI -->
+ <provider android:name="com.android.systemui.keyguard.KeyguardSliceProvider"
+ android:authorities="com.android.systemui.test.keyguard.disabled"
+ android:enabled="false"
+ tools:replace="android:authorities"
+ tools:node="remove" />
+ <provider android:name="com.google.android.systemui.keyguard.KeyguardSliceProviderGoogle"
+ android:authorities="com.android.systemui.test.keyguard.disabled"
+ android:enabled="false"
+ tools:replace="android:authorities"
+ tools:node="remove" />
+ <provider android:name="com.android.keyguard.clock.ClockOptionsProvider"
+ android:authorities="com.android.systemui.test.keyguard.clock.disabled"
+ android:enabled="false"
+ tools:replace="android:authorities"
+ tools:node="remove" />
+ <provider android:name="com.android.systemui.people.PeopleProvider"
+ android:authorities="com.android.systemui.test.people.disabled"
+ android:enabled="false"
+ tools:replace="android:authorities"
+ tools:node="remove" />
+ <provider android:name="androidx.core.content.FileProvider"
+ android:authorities="com.android.systemui.test.fileprovider.disabled"
+ android:enabled="false"
+ tools:replace="android:authorities"
+ tools:node="remove"/>
+ </application>
</manifest>
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
new file mode 100644
index 0000000..2bf1937
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.people.ui.compose
+
+import android.annotation.StringRes
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.LazyListScope
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Divider
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.R
+import com.android.systemui.compose.theme.LocalAndroidColorScheme
+import com.android.systemui.people.ui.viewmodel.PeopleTileViewModel
+import com.android.systemui.people.ui.viewmodel.PeopleViewModel
+import kotlinx.coroutines.flow.collect
+
+/**
+ * Compose the screen associated to a [PeopleViewModel].
+ *
+ * @param viewModel the [PeopleViewModel] that should be composed.
+ * @param onResult the callback called with the result of this screen. Callers should usually finish
+ * the Activity/Fragment/View hosting this Composable once a result is available.
+ */
+@Composable
+fun PeopleScreen(
+ viewModel: PeopleViewModel,
+ onResult: (PeopleViewModel.Result) -> Unit,
+) {
+ val priorityTiles by viewModel.priorityTiles.collectAsState()
+ val recentTiles by viewModel.recentTiles.collectAsState()
+
+ // Make sure to refresh the tiles/conversations when the lifecycle is resumed, so that it
+ // updates them when going back to the Activity after leaving it.
+ val lifecycleOwner = LocalLifecycleOwner.current
+ LaunchedEffect(lifecycleOwner, viewModel) {
+ lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ viewModel.onTileRefreshRequested()
+ }
+ }
+
+ // Call [onResult] this activity when the ViewModel tells us so.
+ LaunchedEffect(viewModel.result) {
+ viewModel.result.collect { result ->
+ if (result != null) {
+ viewModel.clearResult()
+ onResult(result)
+ }
+ }
+ }
+
+ // Make sure to use the Android colors and not the default Material3 colors to have the exact
+ // same colors as the View implementation.
+ val androidColors = LocalAndroidColorScheme.current
+ Surface(
+ color = androidColors.colorBackground,
+ contentColor = androidColors.textColorPrimary,
+ modifier = Modifier.fillMaxSize(),
+ ) {
+ if (priorityTiles.isNotEmpty() || recentTiles.isNotEmpty()) {
+ PeopleScreenWithConversations(priorityTiles, recentTiles, viewModel::onTileClicked)
+ } else {
+ PeopleScreenEmpty(viewModel::onUserJourneyCancelled)
+ }
+ }
+}
+
+@Composable
+private fun PeopleScreenWithConversations(
+ priorityTiles: List<PeopleTileViewModel>,
+ recentTiles: List<PeopleTileViewModel>,
+ onTileClicked: (PeopleTileViewModel) -> Unit,
+) {
+ Column {
+ Column(
+ Modifier.fillMaxWidth().padding(PeopleSpacePadding),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Text(
+ stringResource(R.string.select_conversation_title),
+ style = MaterialTheme.typography.headlineSmall,
+ textAlign = TextAlign.Center,
+ )
+
+ Spacer(Modifier.height(24.dp))
+
+ Text(
+ stringResource(R.string.select_conversation_text),
+ Modifier.padding(horizontal = 24.dp),
+ style = MaterialTheme.typography.bodyLarge,
+ textAlign = TextAlign.Center,
+ )
+ }
+
+ LazyColumn(
+ Modifier.fillMaxWidth(),
+ contentPadding =
+ PaddingValues(
+ top = 16.dp,
+ bottom = PeopleSpacePadding,
+ start = 8.dp,
+ end = 8.dp,
+ )
+ ) {
+ ConversationList(R.string.priority_conversations, priorityTiles, onTileClicked)
+ item { Spacer(Modifier.height(35.dp)) }
+ ConversationList(R.string.recent_conversations, recentTiles, onTileClicked)
+ }
+ }
+}
+
+private fun LazyListScope.ConversationList(
+ @StringRes headerTextResource: Int,
+ tiles: List<PeopleTileViewModel>,
+ onTileClicked: (PeopleTileViewModel) -> Unit
+) {
+ item {
+ Text(
+ stringResource(headerTextResource),
+ Modifier.padding(start = 16.dp),
+ style = MaterialTheme.typography.labelLarge,
+ color = LocalAndroidColorScheme.current.colorAccentPrimaryVariant,
+ )
+
+ Spacer(Modifier.height(10.dp))
+ }
+
+ tiles.forEachIndexed { index, tile ->
+ if (index > 0) {
+ item {
+ Divider(
+ color = LocalAndroidColorScheme.current.colorBackground,
+ thickness = 2.dp,
+ )
+ }
+ }
+
+ item(tile.key.toString()) {
+ Tile(
+ tile,
+ onTileClicked,
+ withTopCornerRadius = index == 0,
+ withBottomCornerRadius = index == tiles.lastIndex,
+ )
+ }
+ }
+}
+
+@Composable
+private fun Tile(
+ tile: PeopleTileViewModel,
+ onTileClicked: (PeopleTileViewModel) -> Unit,
+ withTopCornerRadius: Boolean,
+ withBottomCornerRadius: Boolean,
+) {
+ val androidColors = LocalAndroidColorScheme.current
+ val cornerRadius = dimensionResource(R.dimen.people_space_widget_radius)
+ val topCornerRadius = if (withTopCornerRadius) cornerRadius else 0.dp
+ val bottomCornerRadius = if (withBottomCornerRadius) cornerRadius else 0.dp
+
+ Surface(
+ color = androidColors.colorSurface,
+ contentColor = androidColors.textColorPrimary,
+ shape =
+ RoundedCornerShape(
+ topStart = topCornerRadius,
+ topEnd = topCornerRadius,
+ bottomStart = bottomCornerRadius,
+ bottomEnd = bottomCornerRadius,
+ ),
+ ) {
+ Row(
+ Modifier.fillMaxWidth().clickable { onTileClicked(tile) }.padding(12.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Image(
+ tile.icon.asImageBitmap(),
+ // TODO(b/238993727): Add a content description.
+ contentDescription = null,
+ Modifier.size(dimensionResource(R.dimen.avatar_size_for_medium)),
+ )
+
+ Text(
+ tile.username ?: "",
+ Modifier.padding(horizontal = 16.dp),
+ style = MaterialTheme.typography.titleLarge,
+ )
+ }
+ }
+}
+
+/** The padding applied to the PeopleSpace screen. */
+internal val PeopleSpacePadding = 24.dp
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt
new file mode 100644
index 0000000..5c9358f
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.people.ui.compose
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+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.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import com.android.systemui.R
+import com.android.systemui.compose.theme.LocalAndroidColorScheme
+
+@Composable
+internal fun PeopleScreenEmpty(
+ onGotItClicked: () -> Unit,
+) {
+ Column(
+ Modifier.fillMaxSize().padding(PeopleSpacePadding),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Text(
+ stringResource(R.string.select_conversation_title),
+ style = MaterialTheme.typography.headlineSmall,
+ textAlign = TextAlign.Center,
+ )
+
+ Spacer(Modifier.height(50.dp))
+
+ Text(
+ stringResource(R.string.no_conversations_text),
+ style = MaterialTheme.typography.bodyLarge,
+ textAlign = TextAlign.Center,
+ )
+
+ Spacer(Modifier.weight(1f))
+ ExampleTile()
+ Spacer(Modifier.weight(1f))
+
+ val androidColors = LocalAndroidColorScheme.current
+ Button(
+ onGotItClicked,
+ Modifier.fillMaxWidth().defaultMinSize(minHeight = 56.dp),
+ colors =
+ ButtonDefaults.buttonColors(
+ containerColor = androidColors.colorAccentPrimary,
+ contentColor = androidColors.textColorOnAccent,
+ )
+ ) { Text(stringResource(R.string.got_it)) }
+ }
+}
+
+@Composable
+private fun ExampleTile() {
+ val androidColors = LocalAndroidColorScheme.current
+ Surface(
+ shape = RoundedCornerShape(28.dp),
+ color = androidColors.colorSurface,
+ contentColor = androidColors.textColorPrimary,
+ ) {
+ Row(
+ Modifier.padding(vertical = 20.dp, horizontal = 16.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Column(horizontalAlignment = Alignment.CenterHorizontally) {
+ // TODO(b/238993727): Add a content description.
+ Image(
+ painterResource(R.drawable.ic_avatar_with_badge),
+ contentDescription = null,
+ Modifier.size(40.dp),
+ )
+ Spacer(Modifier.height(2.dp))
+ Text(
+ stringResource(R.string.empty_user_name),
+ style = MaterialTheme.typography.labelMedium,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ )
+ }
+
+ Spacer(Modifier.width(24.dp))
+
+ Text(
+ stringResource(R.string.empty_status),
+ style = MaterialTheme.typography.labelMedium,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/gallery/Android.bp b/packages/SystemUI/compose/gallery/Android.bp
index 40504dc..b0f5cc1 100644
--- a/packages/SystemUI/compose/gallery/Android.bp
+++ b/packages/SystemUI/compose/gallery/Android.bp
@@ -27,6 +27,7 @@
srcs: [
"src/**/*.kt",
+ ":SystemUI-tests-utils",
],
resource_dirs: [
@@ -45,6 +46,14 @@
"androidx.navigation_navigation-compose",
"androidx.appcompat_appcompat",
+
+ // TODO(b/240431193): Remove the dependencies and depend on
+ // SystemUI-test-utils directly.
+ "androidx.test.runner",
+ "mockito-target-extended-minus-junit4",
+ "testables",
+ "truth-prebuilt",
+ "androidx.test.uiautomator",
],
kotlincflags: ["-Xjvm-default=all"],
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
index c341867..bb98fb3 100644
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
@@ -13,7 +13,7 @@
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
@@ -33,6 +33,28 @@
val AndroidColors = ChildScreen("android_colors") { AndroidColorsScreen() }
val ExampleFeature = ChildScreen("example_feature") { ExampleFeatureScreen() }
+ val PeopleEmpty =
+ ChildScreen("people_empty") { navController ->
+ EmptyPeopleScreen(onResult = { navController.popBackStack() })
+ }
+ val PeopleFew =
+ ChildScreen("people_few") { navController ->
+ FewPeopleScreen(onResult = { navController.popBackStack() })
+ }
+ val PeopleFull =
+ ChildScreen("people_full") { navController ->
+ FullPeopleScreen(onResult = { navController.popBackStack() })
+ }
+ val People =
+ ParentScreen(
+ "people",
+ mapOf(
+ "Empty" to PeopleEmpty,
+ "Few" to PeopleFew,
+ "Full" to PeopleFull,
+ )
+ )
+
val Home =
ParentScreen(
"home",
@@ -41,20 +63,21 @@
"Material colors" to MaterialColors,
"Android colors" to AndroidColors,
"Example feature" to ExampleFeature,
+ "People" to People,
)
)
}
/** The main content of the app, that shows [GalleryAppScreens.Home] by default. */
@Composable
-private fun MainContent() {
+private fun MainContent(onControlToggleRequested: () -> Unit) {
Box(Modifier.fillMaxSize()) {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = GalleryAppScreens.Home.identifier,
) {
- screen(GalleryAppScreens.Home, navController)
+ screen(GalleryAppScreens.Home, navController, onControlToggleRequested)
}
}
}
@@ -69,7 +92,7 @@
onChangeTheme: () -> Unit,
) {
val systemFontScale = LocalDensity.current.fontScale
- var fontScale: FontScale by remember {
+ var fontScale: FontScale by rememberSaveable {
mutableStateOf(
FontScale.values().firstOrNull { it.scale == systemFontScale } ?: FontScale.Normal
)
@@ -87,7 +110,7 @@
}
val systemLayoutDirection = LocalLayoutDirection.current
- var layoutDirection by remember { mutableStateOf(systemLayoutDirection) }
+ var layoutDirection by rememberSaveable { mutableStateOf(systemLayoutDirection) }
val onChangeLayoutDirection = {
layoutDirection =
when (layoutDirection) {
@@ -105,19 +128,24 @@
Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
- Column(Modifier.fillMaxSize().systemBarsPadding().padding(16.dp)) {
- ConfigurationControls(
- theme,
- fontScale,
- layoutDirection,
- onChangeTheme,
- onChangeLayoutDirection,
- onChangeFontScale,
- )
+ Column(Modifier.fillMaxSize().systemBarsPadding()) {
+ var showControls by rememberSaveable { mutableStateOf(true) }
- Spacer(Modifier.height(4.dp))
+ if (showControls) {
+ ConfigurationControls(
+ theme,
+ fontScale,
+ layoutDirection,
+ onChangeTheme,
+ onChangeLayoutDirection,
+ onChangeFontScale,
+ Modifier.padding(horizontal = 16.dp),
+ )
- MainContent()
+ Spacer(Modifier.height(4.dp))
+ }
+
+ MainContent(onControlToggleRequested = { showControls = !showControls })
}
}
}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/PeopleScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/PeopleScreen.kt
new file mode 100644
index 0000000..2f0df77
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/PeopleScreen.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.compose.gallery
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+import com.android.systemui.people.emptyPeopleSpaceViewModel
+import com.android.systemui.people.fewPeopleSpaceViewModel
+import com.android.systemui.people.fullPeopleSpaceViewModel
+import com.android.systemui.people.ui.compose.PeopleScreen
+import com.android.systemui.people.ui.viewmodel.PeopleViewModel
+
+@Composable
+fun EmptyPeopleScreen(onResult: (PeopleViewModel.Result) -> Unit) {
+ val context = LocalContext.current.applicationContext
+ val viewModel = emptyPeopleSpaceViewModel(context)
+ PeopleScreen(viewModel, onResult)
+}
+
+@Composable
+fun FewPeopleScreen(onResult: (PeopleViewModel.Result) -> Unit) {
+ val context = LocalContext.current.applicationContext
+ val viewModel = fewPeopleSpaceViewModel(context)
+ PeopleScreen(viewModel, onResult)
+}
+
+@Composable
+fun FullPeopleScreen(onResult: (PeopleViewModel.Result) -> Unit) {
+ val context = LocalContext.current.applicationContext
+ val viewModel = fullPeopleSpaceViewModel(context)
+ PeopleScreen(viewModel, onResult)
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/Screen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/Screen.kt
index 467dac04..d7d0d72 100644
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/Screen.kt
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/Screen.kt
@@ -52,17 +52,29 @@
) : Screen(identifier)
/** Create the navigation graph for [screen]. */
-fun NavGraphBuilder.screen(screen: Screen, navController: NavController) {
+fun NavGraphBuilder.screen(
+ screen: Screen,
+ navController: NavController,
+ onControlToggleRequested: () -> Unit,
+) {
when (screen) {
is ChildScreen -> composable(screen.identifier) { screen.content(navController) }
is ParentScreen -> {
val menuRoute = "${screen.identifier}_menu"
navigation(startDestination = menuRoute, route = screen.identifier) {
// The menu to navigate to one of the children screens.
- composable(menuRoute) { ScreenMenu(screen, navController) }
+ composable(menuRoute) {
+ ScreenMenu(screen, navController, onControlToggleRequested)
+ }
// The content of the child screens.
- screen.children.forEach { (_, child) -> screen(child, navController) }
+ screen.children.forEach { (_, child) ->
+ screen(
+ child,
+ navController,
+ onControlToggleRequested,
+ )
+ }
}
}
}
@@ -72,8 +84,27 @@
private fun ScreenMenu(
screen: ParentScreen,
navController: NavController,
+ onControlToggleRequested: () -> Unit,
) {
- LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
+ LazyColumn(
+ Modifier.padding(horizontal = 16.dp),
+ verticalArrangement = Arrangement.spacedBy(8.dp),
+ ) {
+ item {
+ Surface(
+ Modifier.fillMaxWidth(),
+ color = MaterialTheme.colorScheme.tertiaryContainer,
+ shape = CircleShape,
+ ) {
+ Column(
+ Modifier.clickable(onClick = onControlToggleRequested).padding(16.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Text("Toggle controls")
+ }
+ }
+ }
+
screen.children.forEach { (name, child) ->
item {
Surface(
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/people/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/people/Fakes.kt
new file mode 100644
index 0000000..0966c32
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/people/Fakes.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.people
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.drawable.Icon
+import androidx.core.graphics.drawable.toIcon
+import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.people.data.model.PeopleTileModel
+import com.android.systemui.people.ui.viewmodel.PeopleViewModel
+import com.android.systemui.people.widget.PeopleTileKey
+
+/** A [PeopleViewModel] that does not have any conversations. */
+fun emptyPeopleSpaceViewModel(@Application context: Context): PeopleViewModel {
+ return fakePeopleSpaceViewModel(context, emptyList(), emptyList())
+}
+
+/** A [PeopleViewModel] that has a few conversations. */
+fun fewPeopleSpaceViewModel(@Application context: Context): PeopleViewModel {
+ return fakePeopleSpaceViewModel(
+ context,
+ priorityTiles =
+ listOf(
+ fakeTile(context, id = "0", Color.RED, "Priority"),
+ fakeTile(context, id = "1", Color.BLUE, "Priority NewStory", hasNewStory = true),
+ ),
+ recentTiles =
+ listOf(
+ fakeTile(context, id = "2", Color.GREEN, "Recent Important", isImportant = true),
+ fakeTile(context, id = "3", Color.CYAN, "Recent DndBlocking", isDndBlocking = true),
+ ),
+ )
+}
+
+/** A [PeopleViewModel] that has a lot of conversations. */
+fun fullPeopleSpaceViewModel(@Application context: Context): PeopleViewModel {
+ return fakePeopleSpaceViewModel(
+ context,
+ priorityTiles =
+ listOf(
+ fakeTile(context, id = "0", Color.RED, "Priority"),
+ fakeTile(context, id = "1", Color.BLUE, "Priority NewStory", hasNewStory = true),
+ fakeTile(context, id = "2", Color.GREEN, "Priority Important", isImportant = true),
+ fakeTile(
+ context,
+ id = "3",
+ Color.CYAN,
+ "Priority DndBlocking",
+ isDndBlocking = true,
+ ),
+ fakeTile(
+ context,
+ id = "4",
+ Color.MAGENTA,
+ "Priority NewStory Important",
+ hasNewStory = true,
+ isImportant = true,
+ ),
+ ),
+ recentTiles =
+ listOf(
+ fakeTile(
+ context,
+ id = "5",
+ Color.RED,
+ "Recent NewStory DndBlocking",
+ hasNewStory = true,
+ isDndBlocking = true,
+ ),
+ fakeTile(
+ context,
+ id = "6",
+ Color.BLUE,
+ "Recent Important DndBlocking",
+ isImportant = true,
+ isDndBlocking = true,
+ ),
+ fakeTile(
+ context,
+ id = "7",
+ Color.GREEN,
+ "Recent NewStory Important DndBlocking",
+ hasNewStory = true,
+ isImportant = true,
+ isDndBlocking = true,
+ ),
+ fakeTile(context, id = "8", Color.CYAN, "Recent"),
+ fakeTile(context, id = "9", Color.MAGENTA, "Recent"),
+ ),
+ )
+}
+
+private fun fakePeopleSpaceViewModel(
+ @Application context: Context,
+ priorityTiles: List<PeopleTileModel>,
+ recentTiles: List<PeopleTileModel>,
+): PeopleViewModel {
+ return PeopleViewModel(
+ context,
+ FakePeopleTileRepository(priorityTiles, recentTiles),
+ FakePeopleWidgetRepository(),
+ )
+}
+
+private fun fakeTile(
+ @Application context: Context,
+ id: String,
+ iconColor: Int,
+ username: String,
+ hasNewStory: Boolean = false,
+ isImportant: Boolean = false,
+ isDndBlocking: Boolean = false
+): PeopleTileModel {
+ return PeopleTileModel(
+ PeopleTileKey(id, /* userId= */ 0, /* packageName */ ""),
+ username,
+ fakeUserIcon(context, iconColor),
+ hasNewStory,
+ isImportant,
+ isDndBlocking,
+ )
+}
+
+private fun fakeUserIcon(@Application context: Context, color: Int): Icon {
+ val size = context.resources.getDimensionPixelSize(R.dimen.avatar_size_for_medium)
+ val bitmap =
+ Bitmap.createBitmap(
+ size,
+ size,
+ Bitmap.Config.ARGB_8888,
+ )
+ val canvas = Canvas(bitmap)
+ val paint = Paint().apply { this.color = color }
+ val radius = size / 2f
+ canvas.drawCircle(/* cx= */ radius, /* cy= */ radius, /* radius= */ radius, paint)
+ return bitmap.toIcon()
+}
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index babe924..8fa2204 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -37,8 +37,8 @@
<!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's wirelessly charging. [CHAR LIMIT=50] -->
<string name="keyguard_plugged_in_wireless"><xliff:g id="percentage" example="20%">%s</xliff:g> • Charging wirelessly</string>
- <!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's dock charging. [CHAR LIMIT=50] -->
- <string name="keyguard_plugged_in_dock"><xliff:g id="percentage" example="20%">%s</xliff:g> • Charging Dock</string>
+ <!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's charging. [CHAR LIMIT=50] -->
+ <string name="keyguard_plugged_in_dock"><xliff:g id="percentage" example="20%">%s</xliff:g> • Charging</string>
<!-- When the lock screen is showing and the phone plugged in, and the battery
is not fully charged, say that it's charging. -->
@@ -53,7 +53,7 @@
<string name="keyguard_plugged_in_charging_slowly"><xliff:g id="percentage">%s</xliff:g> • Charging slowly</string>
<!-- When the lock screen is showing and the phone plugged in, and the defend mode is triggered, say that charging is temporarily limited. -->
- <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Charging temporarily limited</string>
+ <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Charging is paused to protect battery</string>
<!-- On the keyguard screen, when pattern lock is disabled, only tell them to press menu to unlock. This is shown in small font at the bottom. -->
<string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string>
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
index 7a57293..3bf44a4 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
@@ -20,10 +20,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/clock"
- android:includeFontPadding="false"
android:textColor="@android:color/white"
android:format12Hour="@string/dream_time_complication_12_hr_time_format"
android:format24Hour="@string/dream_time_complication_24_hr_time_format"
android:shadowColor="@color/keyguard_shadow_color"
android:shadowRadius="?attr/shadowRadius"
+ android:fontFeatureSettings="pnum, lnum"
+ android:letterSpacing="0.02"
android:textSize="@dimen/dream_overlay_complication_clock_time_text_size"/>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f344721..2298584 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1459,7 +1459,7 @@
<dimen name="dream_overlay_status_bar_extra_margin">16dp</dimen>
<!-- Dream overlay complications related dimensions -->
- <dimen name="dream_overlay_complication_clock_time_text_size">100sp</dimen>
+ <dimen name="dream_overlay_complication_clock_time_text_size">86sp</dimen>
<dimen name="dream_overlay_complication_clock_subtitle_text_size">24sp</dimen>
<dimen name="dream_overlay_complication_preview_text_size">36sp</dimen>
<dimen name="dream_overlay_complication_preview_icon_padding">28dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7f3caec..e4fefc7 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -884,7 +884,7 @@
<string name="keyguard_indication_charging_time_slowly"><xliff:g id="percentage">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="charging_time_left" example="4 hr, 2 min">%1$s</xliff:g></string>
<!-- Indication on the keyguard that is shown when the device is dock charging. [CHAR LIMIT=80]-->
- <string name="keyguard_indication_charging_time_dock"><xliff:g id="percentage" example="20%">%2$s</xliff:g> • Charging Dock • Full in <xliff:g id="charging_time_left" example="4 hr, 2 min">%1$s</xliff:g></string>
+ <string name="keyguard_indication_charging_time_dock"><xliff:g id="percentage" example="20%">%2$s</xliff:g> • Charging • Full in <xliff:g id="charging_time_left" example="4 hr, 2 min">%1$s</xliff:g></string>
<!-- Related to user switcher --><skip/>
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
index 60130e1..47e2d2c 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
@@ -44,9 +44,13 @@
import platform.test.screenshot.MaterialYouColorsRule
import platform.test.screenshot.ScreenshotTestRule
import platform.test.screenshot.getEmulatedDevicePathConfig
+import platform.test.screenshot.matchers.BitmapMatcher
/** A rule for View screenshot diff unit tests. */
-class ViewScreenshotTestRule(emulationSpec: DeviceEmulationSpec) : TestRule {
+class ViewScreenshotTestRule(
+ emulationSpec: DeviceEmulationSpec,
+ private val matcher: BitmapMatcher = UnitTestBitmapMatcher
+) : TestRule {
private val colorsRule = MaterialYouColorsRule()
private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
private val screenshotRule =
@@ -59,7 +63,6 @@
.around(deviceEmulationRule)
.around(screenshotRule)
.around(activityRule)
- private val matcher = UnitTestBitmapMatcher
override fun apply(base: Statement, description: Description): Statement {
return delegateRule.apply(base, description)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 2739d59..c2fda82 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -47,7 +47,12 @@
defStyleRes: Int = 0
) : TextView(context, attrs, defStyleAttr, defStyleRes) {
- private var lastMeasureCall: CharSequence = ""
+ private var lastMeasureCall: CharSequence? = null
+ private var lastDraw: CharSequence? = null
+ private var lastTextUpdate: CharSequence? = null
+ private var lastOnTextChanged: CharSequence? = null
+ private var lastInvalidate: CharSequence? = null
+ private var lastTimeZoneChange: CharSequence? = null
private val time = Calendar.getInstance()
@@ -69,6 +74,8 @@
private var textAnimator: TextAnimator? = null
private var onTextAnimatorInitialized: Runnable? = null
+ var timeOverrideInMillis: Long? = null
+
val dozingWeight: Int
get() = if (useBoldedVersion()) dozingWeightInternal + 100 else dozingWeightInternal
@@ -125,7 +132,7 @@
}
fun refreshTime() {
- time.timeInMillis = System.currentTimeMillis()
+ time.timeInMillis = timeOverrideInMillis ?: System.currentTimeMillis()
contentDescription = DateFormat.format(descFormat, time)
val formattedText = DateFormat.format(format, time)
// Setting text actually triggers a layout pass (because the text view is set to
@@ -133,18 +140,19 @@
// relayout if the text didn't actually change.
if (!TextUtils.equals(text, formattedText)) {
text = formattedText
+ lastTextUpdate = getTimestamp()
}
}
fun onTimeZoneChanged(timeZone: TimeZone?) {
time.timeZone = timeZone
refreshFormat()
+ lastTimeZoneChange = "${getTimestamp()} timeZone=${time.timeZone}"
}
@SuppressLint("DrawAllocation")
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
- lastMeasureCall = DateFormat.format(descFormat, System.currentTimeMillis())
val animator = textAnimator
if (animator == null) {
textAnimator = TextAnimator(layout) { invalidate() }
@@ -153,13 +161,34 @@
} else {
animator.updateLayout(layout)
}
+ lastMeasureCall = getTimestamp()
}
override fun onDraw(canvas: Canvas) {
+ lastDraw = getTimestamp()
// intentionally doesn't call super.onDraw here or else the text will be rendered twice
textAnimator?.draw(canvas)
}
+ override fun invalidate() {
+ super.invalidate()
+ lastInvalidate = getTimestamp()
+ }
+
+ private fun getTimestamp(): CharSequence {
+ return "${DateFormat.format("HH:mm:ss", System.currentTimeMillis())} text=$text"
+ }
+
+ override fun onTextChanged(
+ text: CharSequence,
+ start: Int,
+ lengthBefore: Int,
+ lengthAfter: Int
+ ) {
+ super.onTextChanged(text, start, lengthBefore, lengthAfter)
+ lastOnTextChanged = "${getTimestamp()}"
+ }
+
fun setLineSpacingScale(scale: Float) {
lineSpacingScale = scale
setLineSpacing(0f, lineSpacingScale)
@@ -352,7 +381,12 @@
pw.println(" measuredWidth=$measuredWidth")
pw.println(" measuredHeight=$measuredHeight")
pw.println(" singleLineInternal=$isSingleLineInternal")
+ pw.println(" lastTextUpdate=$lastTextUpdate")
+ pw.println(" lastOnTextChanged=$lastOnTextChanged")
+ pw.println(" lastInvalidate=$lastInvalidate")
pw.println(" lastMeasureCall=$lastMeasureCall")
+ pw.println(" lastDraw=$lastDraw")
+ pw.println(" lastTimeZoneChange=$lastTimeZoneChange")
pw.println(" currText=$text")
pw.println(" currTimeContextDesc=$contentDescription")
pw.println(" time=$time")
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
index 1d6a3bf..c7d5ffe 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
@@ -128,6 +128,13 @@
mCallback = samplingCallback;
}
+ /**
+ * Make callback accessible
+ */
+ @VisibleForTesting
+ public SamplingCallback getCallback() {
+ return mCallback;
+ }
private void onDraw() {
if (mWaitingOnDraw) {
mWaitingOnDraw = false;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt
new file mode 100644
index 0000000..344fdb8
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt
@@ -0,0 +1,10 @@
+package com.android.systemui.shared.regionsampling
+
+/**
+ * Enum for whether clock region is dark or light.
+ */
+enum class RegionDarkness(val isDark: Boolean) {
+ DEFAULT(false),
+ DARK(true),
+ LIGHT(false)
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt
new file mode 100644
index 0000000..0146795
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.shared.regionsampling
+
+import android.graphics.Rect
+import android.view.View
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.shared.navigationbar.RegionSamplingHelper
+import com.android.systemui.shared.navigationbar.RegionSamplingHelper.SamplingCallback
+import java.io.PrintWriter
+import java.util.concurrent.Executor
+
+/**
+ * Class for instance of RegionSamplingHelper
+ */
+open class RegionSamplingInstance(
+ sampledView: View?,
+ mainExecutor: Executor?,
+ bgExecutor: Executor?,
+ regionSamplingEnabled: Boolean,
+ updateFun: UpdateColorCallback
+) {
+ private var isDark = RegionDarkness.DEFAULT
+ private var samplingBounds = Rect()
+ @VisibleForTesting var regionSampler: RegionSamplingHelper? = null
+
+ /**
+ * Interface for method to be passed into RegionSamplingHelper
+ */
+ @FunctionalInterface
+ interface UpdateColorCallback {
+ /**
+ * Method to update the text colors after clock darkness changed.
+ */
+ fun updateColors()
+ }
+
+ @VisibleForTesting
+ open fun createRegionSamplingHelper(
+ sampledView: View,
+ callback: SamplingCallback,
+ mainExecutor: Executor?,
+ bgExecutor: Executor?
+ ): RegionSamplingHelper {
+ return RegionSamplingHelper(sampledView, callback, mainExecutor, bgExecutor)
+ }
+
+ private fun convertToClockDarkness(isRegionDark: Boolean): RegionDarkness {
+ return if (isRegionDark) {
+ RegionDarkness.DARK
+ } else {
+ RegionDarkness.LIGHT
+ }
+ }
+
+ fun currentRegionDarkness(): RegionDarkness {
+ return isDark
+ }
+
+ /**
+ * Start region sampler
+ */
+ fun startRegionSampler() {
+ regionSampler?.start(samplingBounds)
+ }
+
+ /**
+ * Stop region sampler
+ */
+ fun stopRegionSampler() {
+ regionSampler?.stop()
+ }
+
+ /**
+ * Dump region sampler
+ */
+ fun dump(pw: PrintWriter) {
+ regionSampler?.dump(pw)
+ }
+
+ init {
+ if (regionSamplingEnabled && sampledView != null) {
+ regionSampler = createRegionSamplingHelper(sampledView,
+ object : SamplingCallback {
+ override fun onRegionDarknessChanged(isRegionDark: Boolean) {
+ isDark = convertToClockDarkness(isRegionDark)
+ updateFun.updateColors()
+ }
+
+ override fun getSampledRegion(sampledView: View): Rect {
+ samplingBounds = Rect(sampledView.left, sampledView.top,
+ sampledView.right, sampledView.bottom)
+ return samplingBounds
+ }
+
+ override fun isSamplingEnabled(): Boolean {
+ return regionSamplingEnabled
+ }
+ }, mainExecutor, bgExecutor)
+ }
+ regionSampler?.setWindowVisible(true)
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
index b29dc83..22bffda 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
@@ -49,6 +49,7 @@
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
@@ -99,6 +100,7 @@
private @WindowInsetsController.Behavior
int mBehavior = WindowInsetsController.BEHAVIOR_DEFAULT;
private int mNavBarMode;
+ private boolean mTaskBarVisible = false;
private boolean mSkipOverrideUserLockPrefsOnce;
private final int mLightIconColor;
private final int mDarkIconColor;
@@ -422,6 +424,7 @@
}
public void onTaskbarStateChange(boolean visible, boolean stashed) {
+ mTaskBarVisible = visible;
if (getRotationButton() == null) {
return;
}
@@ -438,9 +441,12 @@
* Return true when either the task bar is visible or it's in visual immersive mode.
*/
@SuppressLint("InlinedApi")
- private boolean canShowRotationButton() {
- return mIsNavigationBarShowing || mBehavior == WindowInsetsController.BEHAVIOR_DEFAULT
- || isGesturalMode(mNavBarMode);
+ @VisibleForTesting
+ boolean canShowRotationButton() {
+ return mIsNavigationBarShowing
+ || mBehavior == WindowInsetsController.BEHAVIOR_DEFAULT
+ || isGesturalMode(mNavBarMode)
+ || mTaskBarVisible;
}
@DrawableRes
@@ -624,4 +630,3 @@
}
}
}
-
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 206b8be..9164108 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -88,6 +88,7 @@
private int mClockSwitchYAmount;
@VisibleForTesting boolean mChildrenAreLaidOut = false;
+ @VisibleForTesting boolean mAnimateOnLayout = true;
public KeyguardClockSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -305,7 +306,7 @@
super.onLayout(changed, l, t, r, b);
if (mDisplayedClockSize != null && !mChildrenAreLaidOut) {
- post(() -> updateClockViews(mDisplayedClockSize == LARGE, /* animate */ true));
+ post(() -> updateClockViews(mDisplayedClockSize == LARGE, mAnimateOnLayout));
}
mChildrenAreLaidOut = true;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index cf50f7f..d1589b2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -517,8 +517,6 @@
scaledMajor);
Log.v(TAG, "onTouch | finger down: " + touchInfo);
mTouchLogTime = mSystemClock.elapsedRealtime();
- mPowerManager.userActivity(mSystemClock.uptimeMillis(),
- PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
handled = true;
} else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) {
Log.v(TAG, "onTouch | finger move: " + touchInfo);
@@ -846,6 +844,9 @@
return;
}
mLatencyTracker.onActionStart(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
+ // Refresh screen timeout and boost process priority if possible.
+ mPowerManager.userActivity(mSystemClock.uptimeMillis(),
+ PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
if (!mOnFingerDown) {
playStartHaptic();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
index 49e378e..d96476f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
@@ -99,12 +99,11 @@
mProgressColor = context.getColor(R.color.udfps_enroll_progress);
final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
mIsAccessibilityEnabled = am.isTouchExplorationEnabled();
+ mOnFirstBucketFailedColor = context.getColor(R.color.udfps_moving_target_fill_error);
if (!mIsAccessibilityEnabled) {
mHelpColor = context.getColor(R.color.udfps_enroll_progress_help);
- mOnFirstBucketFailedColor = context.getColor(R.color.udfps_moving_target_fill_error);
} else {
mHelpColor = context.getColor(R.color.udfps_enroll_progress_help_with_talkback);
- mOnFirstBucketFailedColor = mHelpColor;
}
mCheckmarkDrawable = context.getDrawable(R.drawable.udfps_enroll_checkmark);
mCheckmarkDrawable.mutate();
@@ -167,7 +166,8 @@
}
private void updateProgress(int remainingSteps, int totalSteps, boolean showingHelp) {
- if (mRemainingSteps == remainingSteps && mTotalSteps == totalSteps) {
+ if (mRemainingSteps == remainingSteps && mTotalSteps == totalSteps
+ && mShowingHelp == showingHelp) {
return;
}
@@ -197,6 +197,7 @@
}
}
+ mShowingHelp = showingHelp;
mRemainingSteps = remainingSteps;
mTotalSteps = totalSteps;
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index 47ea27f..0839338 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -30,6 +30,8 @@
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.core.graphics.ColorUtils;
+
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
@@ -42,7 +44,8 @@
* @hide
*/
final class WirelessChargingLayout extends FrameLayout {
- private static final long RIPPLE_ANIMATION_DURATION = 1500;
+ private static final long CIRCLE_RIPPLE_ANIMATION_DURATION = 1500;
+ private static final long ROUNDED_BOX_RIPPLE_ANIMATION_DURATION = 1750;
private static final int SCRIM_COLOR = 0x4C000000;
private static final int SCRIM_FADE_DURATION = 300;
private RippleView mRippleView;
@@ -131,17 +134,30 @@
"backgroundColor", SCRIM_COLOR, Color.TRANSPARENT);
scrimFadeOutAnimator.setDuration(SCRIM_FADE_DURATION);
scrimFadeOutAnimator.setInterpolator(Interpolators.LINEAR);
- scrimFadeOutAnimator.setStartDelay(RIPPLE_ANIMATION_DURATION - SCRIM_FADE_DURATION);
+ scrimFadeOutAnimator.setStartDelay((rippleShape == RippleShape.CIRCLE
+ ? CIRCLE_RIPPLE_ANIMATION_DURATION : ROUNDED_BOX_RIPPLE_ANIMATION_DURATION)
+ - SCRIM_FADE_DURATION);
AnimatorSet animatorSetScrim = new AnimatorSet();
animatorSetScrim.playTogether(scrimFadeInAnimator, scrimFadeOutAnimator);
animatorSetScrim.start();
mRippleView = findViewById(R.id.wireless_charging_ripple);
mRippleView.setupShader(rippleShape);
+ if (mRippleView.getRippleShape() == RippleShape.ROUNDED_BOX) {
+ mRippleView.setDuration(ROUNDED_BOX_RIPPLE_ANIMATION_DURATION);
+ mRippleView.setSparkleStrength(0.22f);
+ int color = Utils.getColorAttr(mRippleView.getContext(),
+ android.R.attr.colorAccent).getDefaultColor();
+ mRippleView.setColor(ColorUtils.setAlphaComponent(color, 28));
+ } else {
+ mRippleView.setDuration(CIRCLE_RIPPLE_ANIMATION_DURATION);
+ mRippleView.setColor(Utils.getColorAttr(mRippleView.getContext(),
+ android.R.attr.colorAccent).getDefaultColor());
+ }
+
OnAttachStateChangeListener listener = new OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View view) {
- mRippleView.setDuration(RIPPLE_ANIMATION_DURATION);
mRippleView.startRipple();
mRippleView.removeOnAttachStateChangeListener(this);
}
@@ -232,13 +248,13 @@
int height = getMeasuredHeight();
mRippleView.setCenter(width * 0.5f, height * 0.5f);
if (mRippleView.getRippleShape() == RippleShape.ROUNDED_BOX) {
- mRippleView.setMaxSize(width * 1.5f, height * 1.5f);
+ // Those magic numbers are introduced for visual polish. This aspect ratio maps with
+ // the tablet's docking station.
+ mRippleView.setMaxSize(width * 1.36f, height * 1.46f);
} else {
float maxSize = Math.max(width, height);
mRippleView.setMaxSize(maxSize, maxSize);
}
- mRippleView.setColor(Utils.getColorAttr(mRippleView.getContext(),
- android.R.attr.colorAccent).getDefaultColor());
}
super.onLayout(changed, left, top, right, bottom);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f32ea35..2dadf57 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -18,6 +18,7 @@
import android.app.INotificationManager;
import android.content.Context;
+import android.service.dreams.IDreamManager;
import androidx.annotation.Nullable;
@@ -213,6 +214,7 @@
ShadeController shadeController,
@Nullable IStatusBarService statusBarService,
INotificationManager notificationManager,
+ IDreamManager dreamManager,
NotificationVisibilityProvider visibilityProvider,
NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
@@ -230,6 +232,7 @@
shadeController,
statusBarService,
notificationManager,
+ dreamManager,
visibilityProvider,
interruptionStateProvider,
zenModeController,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
index 7e4a108..823255c 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
@@ -113,7 +113,7 @@
}
void setExtraStatusBarItemViews(List<View> views) {
- mSystemStatusViewGroup.removeAllViews();
+ removeAllStatusBarItemViews();
views.forEach(view -> mSystemStatusViewGroup.addView(view));
}
@@ -121,4 +121,8 @@
final View statusIcon = findViewById(resId);
return Objects.requireNonNull(statusIcon);
}
+
+ void removeAllStatusBarItemViews() {
+ mSystemStatusViewGroup.removeAllViews();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index 65cfae1..6f50550 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -192,6 +192,7 @@
mDreamOverlayNotificationCountProvider.ifPresent(
provider -> provider.removeCallback(mNotificationCountCallback));
mStatusBarItemsProvider.removeCallback(mStatusBarItemsProviderCallback);
+ mView.removeAllStatusBarItemViews();
mTouchInsetSession.clear();
mIsAttached = false;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
index 5250d44..7d9f105 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
@@ -37,7 +37,7 @@
public interface DreamClockTimeComplicationModule {
String DREAM_CLOCK_TIME_COMPLICATION_VIEW = "clock_time_complication_view";
String TAG_WEIGHT = "'wght' ";
- int WEIGHT = 200;
+ int WEIGHT = 400;
/**
* Provides the complication view.
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 3029f3c..d87ed57 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -152,8 +152,8 @@
public static final ResourceBooleanFlag STATUS_BAR_USER_SWITCHER =
new ResourceBooleanFlag(602, R.bool.flag_user_switcher_chip);
- public static final UnreleasedFlag STATUS_BAR_LETTERBOX_APPEARANCE =
- new UnreleasedFlag(603, false);
+ public static final ReleasedFlag STATUS_BAR_LETTERBOX_APPEARANCE =
+ new ReleasedFlag(603, false);
public static final UnreleasedFlag NEW_STATUS_BAR_PIPELINE = new UnreleasedFlag(604, true);
@@ -174,11 +174,16 @@
new ResourceBooleanFlag(800, R.bool.flag_monet);
/***************************************/
+ // 801 - region sampling
+ public static final UnreleasedFlag REGION_SAMPLING = new UnreleasedFlag(801);
+
+ /***************************************/
// 900 - media
public static final ReleasedFlag MEDIA_TAP_TO_TRANSFER = new ReleasedFlag(900);
public static final UnreleasedFlag MEDIA_SESSION_ACTIONS = new UnreleasedFlag(901);
public static final ReleasedFlag MEDIA_NEARBY_DEVICES = new ReleasedFlag(903);
public static final ReleasedFlag MEDIA_MUTE_AWAIT = new ReleasedFlag(904);
+ public static final UnreleasedFlag MEDIA_DREAM_COMPLICATION = new UnreleasedFlag(905);
// 1000 - dock
public static final ReleasedFlag SIMULATE_DOCK_THROUGH_CHARGING =
@@ -233,6 +238,7 @@
// 1300 - screenshots
public static final UnreleasedFlag SCREENSHOT_REQUEST_PROCESSOR = new UnreleasedFlag(1300);
+ public static final UnreleasedFlag SCREENSHOT_WORK_PROFILE_POLICY = new UnreleasedFlag(1301);
// Pay no attention to the reflection behind the curtain.
// ========================== Curtain ==========================
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index ca65d12..da5819a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -90,6 +90,8 @@
import android.widget.LinearLayout;
import android.widget.ListPopupWindow;
import android.widget.TextView;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
@@ -155,6 +157,8 @@
public static final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
public static final String SYSTEM_DIALOG_REASON_DREAM = "dream";
+ private static final boolean DEBUG = false;
+
private static final String TAG = "GlobalActionsDialogLite";
private static final String INTERACTION_JANK_TAG = "global_actions";
@@ -2177,6 +2181,11 @@
protected ViewGroup mContainer;
+ private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
+ logOnBackInvocation();
+ dismiss();
+ };
+
@VisibleForTesting
protected GestureDetector.SimpleOnGestureListener mGestureListener =
new GestureDetector.SimpleOnGestureListener() {
@@ -2221,6 +2230,16 @@
}
};
+
+ // this exists so that we can point it to a mock during Unit Testing
+ private OnBackInvokedDispatcher mOverriddenBackDispatcher;
+
+ // the following method exists so that a Unit Test can supply a `OnBackInvokedDispatcher`
+ @VisibleForTesting
+ void setBackDispatcherOverride(OnBackInvokedDispatcher mockDispatcher) {
+ mOverriddenBackDispatcher = mockDispatcher;
+ }
+
ActionsDialogLite(Context context, int themeRes, MyAdapter adapter,
MyOverflowAdapter overflowAdapter,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
@@ -2254,6 +2273,22 @@
super.onCreate(savedInstanceState);
initializeLayout();
mWindowDimAmount = getWindow().getAttributes().dimAmount;
+ getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback);
+ if (DEBUG) Log.d(TAG, "OnBackInvokedCallback handler registered");
+ }
+
+ @VisibleForTesting
+ @Override
+ public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
+ if (mOverriddenBackDispatcher != null) return mOverriddenBackDispatcher;
+ else return super.getOnBackInvokedDispatcher();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mOnBackInvokedCallback);
+ if (DEBUG) Log.d(TAG, "OnBackInvokedCallback handler unregistered");
}
@Override
@@ -2453,7 +2488,12 @@
@Override
public void onBackPressed() {
super.onBackPressed();
+ logOnBackInvocation();
+ }
+
+ private void logOnBackInvocation() {
mUiEventLogger.log(GlobalActionsEvent.GA_CLOSE_BACK);
+ if (DEBUG) Log.d(TAG, "onBack invoked");
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 3eb3c80..6dfbd42 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -323,6 +323,8 @@
if (sEnableRemoteKeyguardOccludeAnimation) {
Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE");
// Register for occluding
+ final RemoteTransition occludeTransition = new RemoteTransition(
+ mOccludeAnimation, getIApplicationThread());
TransitionFilter f = new TransitionFilter();
f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
f.mRequirements = new TransitionFilter.Requirement[]{
@@ -337,10 +339,11 @@
f.mRequirements[1].mMustBeIndependent = false;
f.mRequirements[1].mFlags = FLAG_OCCLUDES_KEYGUARD;
f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
- mShellTransitions.registerRemote(f,
- new RemoteTransition(mOccludeAnimation, getIApplicationThread()));
+ mShellTransitions.registerRemote(f, occludeTransition);
// Now register for un-occlude.
+ final RemoteTransition unoccludeTransition = new RemoteTransition(
+ mUnoccludeAnimation, getIApplicationThread());
f = new TransitionFilter();
f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
f.mRequirements = new TransitionFilter.Requirement[]{
@@ -358,8 +361,23 @@
f.mRequirements[0].mMustBeIndependent = false;
f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD;
f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
- mShellTransitions.registerRemote(f,
- new RemoteTransition(mUnoccludeAnimation, getIApplicationThread()));
+ mShellTransitions.registerRemote(f, unoccludeTransition);
+
+ // Register for specific transition type.
+ // Above filter cannot fulfill all conditions.
+ // E.g. close top activity while screen off but next activity is occluded, this should
+ // an occluded transition, but since the activity is invisible, the condition would
+ // match unoccluded transition.
+ // But on the contrary, if we add above condition in occluded transition, then when user
+ // trying to dismiss occluded activity when unlock keyguard, the condition would match
+ // occluded transition.
+ f = new TransitionFilter();
+ f.mTypeSet = new int[]{TRANSIT_KEYGUARD_OCCLUDE};
+ mShellTransitions.registerRemote(f, occludeTransition);
+
+ f = new TransitionFilter();
+ f.mTypeSet = new int[]{TRANSIT_KEYGUARD_UNOCCLUDE};
+ mShellTransitions.registerRemote(f, unoccludeTransition);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index dbf218a..d4ef467 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2383,10 +2383,10 @@
private void handleHide() {
Trace.beginSection("KeyguardViewMediator#handleHide");
- // It's possible that the device was unlocked in a dream state. It's time to wake up.
- if (mAodShowing || mDreamOverlayShowing) {
- PowerManager pm = mContext.getSystemService(PowerManager.class);
- pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+ // It's possible that the device was unlocked (via BOUNCER) while dozing. It's time to
+ // wake up.
+ if (mAodShowing) {
+ mPM.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
"com.android.systemui:BOUNCER_DOZING");
}
@@ -2415,6 +2415,13 @@
null /* nonApps */, null /* finishedCallback */);
});
}
+
+ // It's possible that the device was unlocked (via BOUNCER or Fingerprint) while
+ // dreaming. It's time to wake up.
+ if (mDreamOverlayShowing) {
+ mPM.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+ "com.android.systemui:UNLOCK_DREAMING");
+ }
}
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index 19c6249..c4e3d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -251,9 +251,21 @@
Utils.getColorAttr(view.context, com.android.internal.R.attr.colorSurface)
view.contentDescription = view.context.getString(viewModel.contentDescriptionResourceId)
- view.setOnClickListener {
+ view.isClickable = viewModel.isClickable
+ if (viewModel.isClickable) {
+ view.setOnClickListener(OnClickListener(viewModel, falsingManager))
+ } else {
+ view.setOnClickListener(null)
+ }
+ }
+
+ private class OnClickListener(
+ private val viewModel: KeyguardQuickAffordanceViewModel,
+ private val falsingManager: FalsingManager,
+ ) : View.OnClickListener {
+ override fun onClick(view: View) {
if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- return@setOnClickListener
+ return
}
if (viewModel.configKey != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
index 01d5e5c..e3ebac6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel
+import androidx.annotation.VisibleForTesting
import com.android.systemui.doze.util.BurnInHelperWrapper
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -37,6 +38,23 @@
private val bottomAreaInteractor: KeyguardBottomAreaInteractor,
private val burnInHelperWrapper: BurnInHelperWrapper,
) {
+ /**
+ * Whether quick affordances are "opaque enough" to be considered visible to and interactive by
+ * the user. If they are not interactive, user input should not be allowed on them.
+ *
+ * Note that there is a margin of error, where we allow very, very slightly transparent views to
+ * be considered "fully opaque" for the purpose of being interactive. This is to accommodate the
+ * error margin of floating point arithmetic.
+ *
+ * A view that is visible but with an alpha of less than our threshold either means it's not
+ * fully done fading in or is fading/faded out. Either way, it should not be
+ * interactive/clickable unless "fully opaque" to avoid issues like in b/241830987.
+ */
+ private val areQuickAffordancesFullyOpaque: Flow<Boolean> =
+ bottomAreaInteractor.alpha
+ .map { alpha -> alpha >= AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD }
+ .distinctUntilChanged()
+
/** An observable for the view-model of the "start button" quick affordance. */
val startButton: Flow<KeyguardQuickAffordanceViewModel> =
button(KeyguardQuickAffordancePosition.BOTTOM_START)
@@ -77,14 +95,19 @@
return combine(
quickAffordanceInteractor.quickAffordance(position),
bottomAreaInteractor.animateDozingTransitions.distinctUntilChanged(),
- ) { model, animateReveal ->
- model.toViewModel(animateReveal)
+ areQuickAffordancesFullyOpaque,
+ ) { model, animateReveal, isFullyOpaque ->
+ model.toViewModel(
+ animateReveal = animateReveal,
+ isClickable = isFullyOpaque,
+ )
}
.distinctUntilChanged()
}
private fun KeyguardQuickAffordanceModel.toViewModel(
animateReveal: Boolean,
+ isClickable: Boolean,
): KeyguardQuickAffordanceViewModel {
return when (this) {
is KeyguardQuickAffordanceModel.Visible ->
@@ -100,8 +123,20 @@
animationController = parameters.animationController,
)
},
+ isClickable = isClickable,
)
is KeyguardQuickAffordanceModel.Hidden -> KeyguardQuickAffordanceViewModel()
}
}
+
+ companion object {
+ // We select a value that's less than 1.0 because we want floating point math precision to
+ // not be a factor in determining whether the affordance UI is fully opaque. The number we
+ // choose needs to be close enough 1.0 such that the user can't easily tell the difference
+ // between the UI with an alpha at the threshold and when the alpha is 1.0. At the same
+ // time, we don't want the number to be too close to 1.0 such that there is a chance that we
+ // never treat the affordance UI as "fully opaque" as that would risk making it forever not
+ // clickable.
+ @VisibleForTesting const val AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD = 0.95f
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
index 985ab62..b1de27d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
@@ -31,6 +31,7 @@
val icon: ContainedDrawable = ContainedDrawable.WithResource(0),
@StringRes val contentDescriptionResourceId: Int = 0,
val onClicked: (OnClickedParameters) -> Unit = {},
+ val isClickable: Boolean = false,
) {
data class OnClickedParameters(
val configKey: KClass<out KeyguardQuickAffordanceConfig>,
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index c858bc3..c2a8764 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -84,6 +84,14 @@
return factory.create("LSShadeTransitionLog", 50);
}
+ /** Provides a logging buffer for Shade messages. */
+ @Provides
+ @SysUISingleton
+ @ShadeLog
+ public static LogBuffer provideShadeLogBuffer(LogBufferFactory factory) {
+ return factory.create("ShadeLog", 500, false);
+ }
+
/** Provides a logging buffer for all logs related to managing notification sections. */
@Provides
@SysUISingleton
@@ -262,7 +270,7 @@
@SysUISingleton
@StatusBarConnectivityLog
public static LogBuffer provideStatusBarConnectivityBuffer(LogBufferFactory factory) {
- return factory.create("StatusBarConnectivityLog", 64);
+ return factory.create("SbConnectivity", 64);
}
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java
new file mode 100644
index 0000000..bd0d298
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/ShadeLog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for Shade touch handling messages. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface ShadeLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
index 237b505..32600fb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
@@ -18,19 +18,25 @@
import android.content.Context
import android.content.res.Configuration
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
import android.view.View
import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.dagger.MediaModule.KEYGUARD
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.MediaContainerView
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.LargeScreenUtils
+import com.android.systemui.util.settings.SecureSettings
import javax.inject.Inject
import javax.inject.Named
@@ -43,9 +49,10 @@
@param:Named(KEYGUARD) private val mediaHost: MediaHost,
private val bypassController: KeyguardBypassController,
private val statusBarStateController: SysuiStatusBarStateController,
- private val notifLockscreenUserManager: NotificationLockscreenUserManager,
private val context: Context,
- configurationController: ConfigurationController
+ private val secureSettings: SecureSettings,
+ @Main private val handler: Handler,
+ configurationController: ConfigurationController,
) {
init {
@@ -60,6 +67,24 @@
}
})
+ val settingsObserver: ContentObserver = object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ if (uri == lockScreenMediaPlayerUri) {
+ allowMediaPlayerOnLockScreen =
+ secureSettings.getBoolForUser(
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ true,
+ UserHandle.USER_CURRENT
+ )
+ refreshMediaPosition()
+ }
+ }
+ }
+ secureSettings.registerContentObserverForUser(
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ settingsObserver,
+ UserHandle.USER_ALL)
+
// First let's set the desired state that we want for this host
mediaHost.expansion = MediaHostState.EXPANDED
mediaHost.showsOnlyActiveMedia = true
@@ -101,6 +126,13 @@
private var splitShadeContainer: ViewGroup? = null
/**
+ * Track the media player setting status on lock screen.
+ */
+ private var allowMediaPlayerOnLockScreen: Boolean = true
+ private val lockScreenMediaPlayerUri =
+ secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
+
+ /**
* Attaches media container in single pane mode, situated at the top of the notifications list
*/
fun attachSinglePaneContainer(mediaView: MediaContainerView?) {
@@ -164,7 +196,7 @@
visible = mediaHost.visible &&
!bypassController.bypassEnabled &&
keyguardOrUserSwitcher &&
- notifLockscreenUserManager.shouldShowLockscreenNotifications()
+ allowMediaPlayerOnLockScreen
if (visible) {
showMediaPlayer()
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 30ba476..c882675 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media
import android.app.Notification
+import android.app.Notification.EXTRA_SUBSTITUTE_APP_NAME
import android.app.PendingIntent
import android.app.smartspace.SmartspaceConfig
import android.app.smartspace.SmartspaceManager
@@ -27,6 +28,7 @@
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.ImageDecoder
@@ -57,8 +59,8 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.BcSmartspaceDataPlugin
-import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
import com.android.systemui.statusbar.NotificationMediaManager.isConnectingState
+import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
import com.android.systemui.statusbar.notification.row.HybridGroupManager
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.Assert
@@ -633,9 +635,14 @@
}
val mediaController = mediaControllerFactory.create(token)
val metadata = mediaController.metadata
+ val notif: Notification = sbn.notification
+
+ val appInfo = notif.extras.getParcelable(
+ Notification.EXTRA_BUILDER_APPLICATION_INFO,
+ ApplicationInfo::class.java
+ ) ?: getAppInfoFromPackage(sbn.packageName)
// Album art
- val notif: Notification = sbn.notification
var artworkBitmap = metadata?.let { loadBitmapFromUri(it) }
if (artworkBitmap == null) {
artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ART)
@@ -650,8 +657,7 @@
}
// App name
- val builder = Notification.Builder.recoverBuilder(context, notif)
- val app = builder.loadHeaderAppName()
+ val appName = getAppName(sbn, appInfo)
// App Icon
val smallIcon = sbn.notification.smallIcon
@@ -712,12 +718,7 @@
val currentEntry = mediaEntries.get(key)
val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
- val appUid = try {
- context.packageManager.getApplicationInfo(sbn.packageName, 0)?.uid!!
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(TAG, "Could not get app UID for ${sbn.packageName}", e)
- Process.INVALID_UID
- }
+ val appUid = appInfo?.uid ?: Process.INVALID_UID
if (logEvent) {
logger.logActiveMediaAdded(appUid, sbn.packageName, instanceId, playbackLocation)
@@ -730,7 +731,7 @@
val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true
val active = mediaEntries[key]?.active ?: true
- onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, app,
+ onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, appName,
smallIcon, artist, song, artWorkIcon, actionIcons, actionsToShowCollapsed,
semanticActions, sbn.packageName, token, notif.contentIntent, device,
active, resumeAction = resumeAction, playbackLocation = playbackLocation,
@@ -740,6 +741,28 @@
}
}
+ private fun getAppInfoFromPackage(packageName: String): ApplicationInfo? {
+ try {
+ return context.packageManager.getApplicationInfo(packageName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Could not get app info for $packageName", e)
+ }
+ return null
+ }
+
+ private fun getAppName(sbn: StatusBarNotification, appInfo: ApplicationInfo?): String {
+ val name = sbn.notification.extras.getString(EXTRA_SUBSTITUTE_APP_NAME)
+ if (name != null) {
+ return name
+ }
+
+ return if (appInfo != null) {
+ context.packageManager.getApplicationLabel(appInfo).toString()
+ } else {
+ sbn.packageName
+ }
+ }
+
/**
* Generate action buttons based on notification actions
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 458ed40..ae4c7c7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -22,7 +22,12 @@
import android.annotation.IntDef
import android.content.Context
import android.content.res.Configuration
+import android.database.ContentObserver
import android.graphics.Rect
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
import android.util.Log
import android.util.MathUtils
import android.view.View
@@ -33,11 +38,12 @@
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dreams.DreamOverlayStateController
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.shade.NotifPanelEvents
import com.android.systemui.statusbar.CrossFadeHelper
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
@@ -46,6 +52,7 @@
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.LargeScreenUtils
import com.android.systemui.util.animation.UniqueObjectHostView
+import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.traceSection
import javax.inject.Inject
@@ -84,14 +91,31 @@
private val keyguardStateController: KeyguardStateController,
private val bypassController: KeyguardBypassController,
private val mediaCarouselController: MediaCarouselController,
- private val notifLockscreenUserManager: NotificationLockscreenUserManager,
+ private val keyguardViewController: KeyguardViewController,
+ private val dreamOverlayStateController: DreamOverlayStateController,
configurationController: ConfigurationController,
wakefulnessLifecycle: WakefulnessLifecycle,
- private val keyguardViewController: KeyguardViewController,
- private val dreamOverlayStateController: DreamOverlayStateController
+ panelEventsEvents: NotifPanelEvents,
+ private val secureSettings: SecureSettings,
+ @Main private val handler: Handler,
) {
/**
+ * Track the media player setting status on lock screen.
+ */
+ private var allowMediaPlayerOnLockScreen: Boolean = true
+ private val lockScreenMediaPlayerUri =
+ secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
+
+ /**
+ * Whether we "skip" QQS during panel expansion.
+ *
+ * This means that when expanding the panel we go directly to QS. Also when we are on QS and
+ * start closing the panel, it fully collapses instead of going to QQS.
+ */
+ private var skipQqsOnExpansion: Boolean = false
+
+ /**
* The root overlay of the hierarchy. This is where the media notification is attached to
* whenever the view is transitioning from one host to another. It also make sure that the
* view is always in its final state when it is attached to a view host.
@@ -504,6 +528,30 @@
mediaCarouselController.updateUserVisibility = {
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
}
+
+ panelEventsEvents.registerListener(object : NotifPanelEvents.Listener {
+ override fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {
+ skipQqsOnExpansion = isExpandImmediateEnabled
+ updateDesiredLocation()
+ }
+ })
+
+ val settingsObserver: ContentObserver = object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ if (uri == lockScreenMediaPlayerUri) {
+ allowMediaPlayerOnLockScreen =
+ secureSettings.getBoolForUser(
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ true,
+ UserHandle.USER_CURRENT
+ )
+ }
+ }
+ }
+ secureSettings.registerContentObserverForUser(
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ settingsObserver,
+ UserHandle.USER_ALL)
}
private fun updateConfiguration() {
@@ -701,6 +749,9 @@
if (isCurrentlyInGuidedTransformation()) {
return false
}
+ if (skipQqsOnExpansion) {
+ return false
+ }
// This is an invalid transition, and can happen when using the camera gesture from the
// lock screen. Disallow.
if (previousLocation == LOCATION_LOCKSCREEN &&
@@ -852,6 +903,9 @@
* otherwise
*/
private fun getTransformationProgress(): Float {
+ if (skipQqsOnExpansion) {
+ return -1.0f
+ }
val progress = getQSTransformationProgress()
if (statusbarState != StatusBarState.KEYGUARD && progress >= 0) {
return progress
@@ -1013,7 +1067,6 @@
}
val onLockscreen = (!bypassController.bypassEnabled &&
(statusbarState == StatusBarState.KEYGUARD))
- val allowedOnLockscreen = notifLockscreenUserManager.shouldShowLockscreenNotifications()
val location = when {
dreamOverlayActive -> LOCATION_DREAM_OVERLAY
(qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS
@@ -1021,7 +1074,7 @@
!hasActiveMedia -> LOCATION_QS
onLockscreen && isSplitShadeExpanding() -> LOCATION_QS
onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS
- onLockscreen && allowedOnLockscreen -> LOCATION_LOCKSCREEN
+ onLockscreen && allowMediaPlayerOnLockScreen -> LOCATION_LOCKSCREEN
else -> LOCATION_QQS
}
// When we're on lock screen and the player is not active, we should keep it in QS.
@@ -1042,6 +1095,10 @@
// reattach it without an animation
return LOCATION_LOCKSCREEN
}
+ if (skipQqsOnExpansion) {
+ // When doing an immediate expand or collapse, we want to keep it in QS.
+ return LOCATION_QS
+ }
return location
}
@@ -1089,7 +1146,7 @@
return !statusBarStateController.isDozing &&
!keyguardViewController.isBouncerShowing &&
statusBarStateController.state == StatusBarState.KEYGUARD &&
- notifLockscreenUserManager.shouldShowLockscreenNotifications() &&
+ allowMediaPlayerOnLockScreen &&
statusBarStateController.isExpanded &&
!qsExpanded
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 4ef98cf..bec130b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -296,27 +296,17 @@
mMediaOutputController.setRefreshing(true);
// Update header icon
final int iconRes = getHeaderIconRes();
- final IconCompat iconCompat = getHeaderIcon();
- final Drawable appSourceDrawable = getAppSourceIcon();
+ final IconCompat headerIcon = getHeaderIcon();
+ final IconCompat appSourceIcon = getAppSourceIcon();
boolean colorSetUpdated = false;
mCastAppLayout.setVisibility(
mMediaOutputController.shouldShowLaunchSection()
? View.VISIBLE : View.GONE);
- if (appSourceDrawable != null) {
- mAppResourceIcon.setImageDrawable(appSourceDrawable);
- mAppButton.setCompoundDrawablesWithIntrinsicBounds(resizeDrawable(appSourceDrawable,
- mContext.getResources().getDimensionPixelSize(
- R.dimen.media_output_dialog_app_tier_icon_size
- )),
- null, null, null);
- } else {
- mAppResourceIcon.setVisibility(View.GONE);
- }
if (iconRes != 0) {
mHeaderIcon.setVisibility(View.VISIBLE);
mHeaderIcon.setImageResource(iconRes);
- } else if (iconCompat != null) {
- Icon icon = iconCompat.toIcon(mContext);
+ } else if (headerIcon != null) {
+ Icon icon = headerIcon.toIcon(mContext);
if (icon.getType() != Icon.TYPE_BITMAP && icon.getType() != Icon.TYPE_ADAPTIVE_BITMAP) {
// icon doesn't support getBitmap, use default value for color scheme
updateButtonBackgroundColorFilter();
@@ -336,6 +326,18 @@
} else {
mHeaderIcon.setVisibility(View.GONE);
}
+ if (appSourceIcon != null) {
+ Icon appIcon = appSourceIcon.toIcon(mContext);
+ mAppResourceIcon.setColorFilter(mMediaOutputController.getColorItemContent());
+ mAppResourceIcon.setImageIcon(appIcon);
+ } else {
+ Drawable appIconDrawable = mMediaOutputController.getAppSourceIconFromPackage();
+ if (appIconDrawable != null) {
+ mAppResourceIcon.setImageDrawable(appIconDrawable);
+ } else {
+ mAppResourceIcon.setVisibility(View.GONE);
+ }
+ }
if (mHeaderIcon.getVisibility() == View.VISIBLE) {
final int size = getHeaderIconSize();
final int padding = mContext.getResources().getDimensionPixelSize(
@@ -480,7 +482,7 @@
}
}
- abstract Drawable getAppSourceIcon();
+ abstract IconCompat getAppSourceIcon();
abstract int getHeaderIconRes();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index 310469d..35baf013 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -19,7 +19,6 @@
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
@@ -116,8 +115,8 @@
}
@Override
- Drawable getAppSourceIcon() {
- return mMediaOutputController.getAppSourceIcon();
+ IconCompat getAppSourceIcon() {
+ return mMediaOutputController.getNotificationSmallIcon();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt
index 0fa3265..2b5d6fd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media.dialog
+import android.app.KeyguardManager
import android.content.Context
import android.media.AudioManager
import android.media.session.MediaSessionManager
@@ -45,7 +46,8 @@
private val dialogLaunchAnimator: DialogLaunchAnimator,
private val nearbyMediaDevicesManagerOptional: Optional<NearbyMediaDevicesManager>,
private val audioManager: AudioManager,
- private val powerExemptionManager: PowerExemptionManager
+ private val powerExemptionManager: PowerExemptionManager,
+ private val keyGuardManager: KeyguardManager
) {
var mediaOutputBroadcastDialog: MediaOutputBroadcastDialog? = null
@@ -57,7 +59,7 @@
val controller = MediaOutputController(context, packageName,
mediaSessionManager, lbm, starter, notifCollection,
dialogLaunchAnimator, nearbyMediaDevicesManagerOptional, audioManager,
- powerExemptionManager)
+ powerExemptionManager, keyGuardManager)
val dialog =
MediaOutputBroadcastDialog(context, aboveStatusBar, broadcastSender, controller)
mediaOutputBroadcastDialog = dialog
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 52dbfe5..dad6544 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -20,6 +20,7 @@
import android.annotation.CallbackExecutor;
import android.app.AlertDialog;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.WallpaperColors;
import android.bluetooth.BluetoothLeBroadcast;
@@ -120,6 +121,7 @@
final List<MediaDevice> mCachedMediaDevices = new CopyOnWriteArrayList<>();
private final AudioManager mAudioManager;
private final PowerExemptionManager mPowerExemptionManager;
+ private final KeyguardManager mKeyGuardManager;
private final NearbyMediaDevicesManager mNearbyMediaDevicesManager;
private final Map<String, Integer> mNearbyDeviceInfoMap = new ConcurrentHashMap<>();
@@ -154,7 +156,8 @@
DialogLaunchAnimator dialogLaunchAnimator,
Optional<NearbyMediaDevicesManager> nearbyMediaDevicesManagerOptional,
AudioManager audioManager,
- PowerExemptionManager powerExemptionManager) {
+ PowerExemptionManager powerExemptionManager,
+ KeyguardManager keyGuardManager) {
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
@@ -163,6 +166,7 @@
mNotifCollection = notifCollection;
mAudioManager = audioManager;
mPowerExemptionManager = powerExemptionManager;
+ mKeyGuardManager = keyGuardManager;
InfoMediaManager imm = new InfoMediaManager(mContext, packageName, null, lbm);
mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
@@ -310,7 +314,7 @@
}
}
- Drawable getAppSourceIcon() {
+ Drawable getAppSourceIconFromPackage() {
if (mPackageName.isEmpty()) {
return null;
}
@@ -421,6 +425,24 @@
|| isSelectedDeviceInGroup;
}
+ IconCompat getNotificationSmallIcon() {
+ if (TextUtils.isEmpty(mPackageName)) {
+ return null;
+ }
+ for (NotificationEntry entry : mNotifCollection.getAllNotifs()) {
+ final Notification notification = entry.getSbn().getNotification();
+ if (notification.isMediaNotification()
+ && TextUtils.equals(entry.getSbn().getPackageName(), mPackageName)) {
+ final Icon icon = notification.getSmallIcon();
+ if (icon == null) {
+ break;
+ }
+ return IconCompat.createFromIcon(icon);
+ }
+ }
+ return null;
+ }
+
IconCompat getNotificationIcon() {
if (TextUtils.isEmpty(mPackageName)) {
return null;
@@ -719,7 +741,8 @@
ActivityLaunchAnimator.Controller controller =
mDialogLaunchAnimator.createActivityLaunchController(view);
- if (controller == null) {
+ if (controller == null || (mKeyGuardManager != null
+ && mKeyGuardManager.isKeyguardLocked())) {
mCallback.dismissDialog();
}
@@ -771,7 +794,7 @@
MediaOutputController controller = new MediaOutputController(mContext, mPackageName,
mMediaSessionManager, mLocalBluetoothManager, mActivityStarter,
mNotifCollection, mDialogLaunchAnimator, Optional.of(mNearbyMediaDevicesManager),
- mAudioManager, mPowerExemptionManager);
+ mAudioManager, mPowerExemptionManager, mKeyGuardManager);
MediaOutputBroadcastDialog dialog = new MediaOutputBroadcastDialog(mContext, true,
broadcastSender, controller);
mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index fc4773d..fbd0079 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -17,7 +17,6 @@
package com.android.systemui.media.dialog;
import android.content.Context;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
@@ -81,8 +80,8 @@
}
@Override
- Drawable getAppSourceIcon() {
- return mMediaOutputController.getAppSourceIcon();
+ IconCompat getAppSourceIcon() {
+ return mMediaOutputController.getNotificationSmallIcon();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index 8249a7c..543efed 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media.dialog
+import android.app.KeyguardManager
import android.content.Context
import android.media.AudioManager
import android.media.session.MediaSessionManager
@@ -47,7 +48,8 @@
private val dialogLaunchAnimator: DialogLaunchAnimator,
private val nearbyMediaDevicesManagerOptional: Optional<NearbyMediaDevicesManager>,
private val audioManager: AudioManager,
- private val powerExemptionManager: PowerExemptionManager
+ private val powerExemptionManager: PowerExemptionManager,
+ private val keyGuardManager: KeyguardManager
) {
companion object {
private const val INTERACTION_JANK_TAG = "media_output"
@@ -63,7 +65,7 @@
context, packageName,
mediaSessionManager, lbm, starter, notifCollection,
dialogLaunchAnimator, nearbyMediaDevicesManagerOptional, audioManager,
- powerExemptionManager)
+ powerExemptionManager, keyGuardManager)
val dialog =
MediaOutputDialog(context, aboveStatusBar, broadcastSender, controller, uiEventLogger)
mediaOutputDialog = dialog
diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
index e077fed..c544871 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
@@ -16,6 +16,8 @@
package com.android.systemui.media.dream;
+import static com.android.systemui.flags.Flags.MEDIA_DREAM_COMPLICATION;
+
import android.content.Context;
import androidx.annotation.NonNull;
@@ -23,6 +25,7 @@
import com.android.systemui.CoreStartable;
import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.MediaData;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.SmartspaceMediaData;
@@ -34,7 +37,7 @@
* the media complication as appropriate
*/
public class MediaDreamSentinel extends CoreStartable {
- private MediaDataManager.Listener mListener = new MediaDataManager.Listener() {
+ private final MediaDataManager.Listener mListener = new MediaDataManager.Listener() {
private boolean mAdded;
@Override
public void onSmartspaceMediaDataRemoved(@NonNull String key, boolean immediately) {
@@ -63,6 +66,10 @@
public void onMediaDataLoaded(@NonNull String key, @Nullable String oldKey,
@NonNull MediaData data, boolean immediately, int receivedSmartspaceCardLatency,
boolean isSsReactivated) {
+ if (!mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)) {
+ return;
+ }
+
if (mAdded) {
return;
}
@@ -79,15 +86,18 @@
private final MediaDataManager mMediaDataManager;
private final DreamOverlayStateController mDreamOverlayStateController;
private final MediaDreamComplication mComplication;
+ private final FeatureFlags mFeatureFlags;
@Inject
public MediaDreamSentinel(Context context, MediaDataManager mediaDataManager,
DreamOverlayStateController dreamOverlayStateController,
- MediaDreamComplication complication) {
+ MediaDreamComplication complication,
+ FeatureFlags featureFlags) {
super(context);
mMediaDataManager = mediaDataManager;
mDreamOverlayStateController = dreamOverlayStateController;
mComplication = complication;
+ mFeatureFlags = featureFlags;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
index 2278938..3a0ac1b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -226,7 +226,7 @@
appIconView.contentDescription = appNameOverride ?: iconInfo.iconName
appIconView.setImageDrawable(appIconDrawableOverride ?: iconInfo.icon)
- return appIconView.contentDescription.toString()
+ return appIconView.contentDescription
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 196ea22..00a22f2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -141,12 +141,13 @@
override fun updateChipView(newChipInfo: ChipReceiverInfo, currentChipView: ViewGroup) {
super.updateChipView(newChipInfo, currentChipView)
- setIcon(
+ val iconName = setIcon(
currentChipView,
newChipInfo.routeInfo.clientPackageName,
newChipInfo.appIconDrawableOverride,
newChipInfo.appNameOverride
)
+ currentChipView.contentDescription = iconName
}
override fun animateChipIn(chipView: ViewGroup) {
@@ -159,6 +160,8 @@
.alpha(1f)
.setDuration(5.frames)
.start()
+ // Using withEndAction{} doesn't apply a11y focus when screen is unlocked.
+ appIconView.postOnAnimation { chipView.requestAccessibilityFocus() }
startRipple(chipView.requireViewById(R.id.ripple))
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/ui/viewmodel/PeopleViewModel.kt b/packages/SystemUI/src/com/android/systemui/people/ui/viewmodel/PeopleViewModel.kt
index 0834a5a..e27bfb3 100644
--- a/packages/SystemUI/src/com/android/systemui/people/ui/viewmodel/PeopleViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/people/ui/viewmodel/PeopleViewModel.kt
@@ -31,7 +31,6 @@
import com.android.systemui.people.data.repository.PeopleTileRepository
import com.android.systemui.people.data.repository.PeopleWidgetRepository
import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -52,7 +51,7 @@
* reactive and you have to manually call [onTileRefreshRequested] to refresh the tiles.
*/
private val _priorityTiles = MutableStateFlow(priorityTiles())
- val priorityTiles: Flow<List<PeopleTileViewModel>> = _priorityTiles.asStateFlow()
+ val priorityTiles: StateFlow<List<PeopleTileViewModel>> = _priorityTiles.asStateFlow()
/**
* The list of the priority tiles/conversations.
@@ -61,7 +60,7 @@
* reactive and you have to manually call [onTileRefreshRequested] to refresh the tiles.
*/
private val _recentTiles = MutableStateFlow(recentTiles())
- val recentTiles: Flow<List<PeopleTileViewModel>> = _recentTiles.asStateFlow()
+ val recentTiles: StateFlow<List<PeopleTileViewModel>> = _recentTiles.asStateFlow()
/** The ID of the widget currently being edited/added. */
private val _appWidgetId = MutableStateFlow(INVALID_APPWIDGET_ID)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 833573d..be44202 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -39,6 +39,7 @@
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Provider;
/** Controller for {@link QuickQSPanel}. */
@QSScope
@@ -52,20 +53,21 @@
}
};
- private final boolean mUsingCollapsedLandscapeMedia;
+ private final Provider<Boolean> mUsingCollapsedLandscapeMediaProvider;
@Inject
QuickQSPanelController(QuickQSPanel view, QSTileHost qsTileHost,
QSCustomizerController qsCustomizerController,
@Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
@Named(QUICK_QS_PANEL) MediaHost mediaHost,
- @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA) boolean usingCollapsedLandscapeMedia,
+ @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA)
+ Provider<Boolean> usingCollapsedLandscapeMediaProvider,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
DumpManager dumpManager
) {
super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
uiEventLogger, qsLogger, dumpManager);
- mUsingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia;
+ mUsingCollapsedLandscapeMediaProvider = usingCollapsedLandscapeMediaProvider;
}
@Override
@@ -80,7 +82,8 @@
int rotation = getRotation();
boolean isLandscape = rotation == RotationUtils.ROTATION_LANDSCAPE
|| rotation == RotationUtils.ROTATION_SEASCAPE;
- if (!mUsingCollapsedLandscapeMedia || !isLandscape) {
+ boolean usingCollapsedLandscapeMedia = mUsingCollapsedLandscapeMediaProvider.get();
+ if (!usingCollapsedLandscapeMedia || !isLandscape) {
mMediaHost.setExpansion(MediaHost.EXPANDED);
} else {
mMediaHost.setExpansion(MediaHost.COLLAPSED);
@@ -126,7 +129,6 @@
super.setTiles(tiles, /* collapsedView */ true);
}
- /** */
public void setContentMargins(int marginStart, int marginEnd) {
mView.setContentMargins(marginStart, marginEnd, mMediaHost.getHostView());
}
diff --git a/packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt b/packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt
index 56a1874..db7c1fd 100644
--- a/packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt
+++ b/packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt
@@ -67,7 +67,7 @@
float rippleInsideAlpha = (1.-inside) * in_fadeFill;
float rippleRingAlpha = (1.-sparkleRing) * in_fadeRing;
- float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * 0.45;
+ float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * in_color.a;
vec4 ripple = in_color * rippleAlpha;
return mix(ripple, vec4(sparkle), sparkle * in_sparkle_strength);
}
@@ -83,7 +83,7 @@
float rippleInsideAlpha = (1.-inside) * in_fadeFill;
float rippleRingAlpha = (1.-sparkleRing) * in_fadeRing;
- float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * 0.45;
+ float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * in_color.a;
vec4 ripple = in_color * rippleAlpha;
return mix(ripple, vec4(sparkle), sparkle * in_sparkle_strength);
}
@@ -99,7 +99,7 @@
float rippleInsideAlpha = (1.-inside) * in_fadeFill;
float rippleRingAlpha = (1.-sparkleRing) * in_fadeRing;
- float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * 0.45;
+ float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * in_color.a;
vec4 ripple = in_color * rippleAlpha;
return mix(ripple, vec4(sparkle), sparkle * in_sparkle_strength);
}
diff --git a/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt b/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
index 8b01201..60c8f37 100644
--- a/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
@@ -81,6 +81,7 @@
rippleShader.color = RIPPLE_DEFAULT_COLOR
rippleShader.progress = 0f
rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH
+ rippleShader.pixelDensity = resources.displayMetrics.density
ripplePaint.shader = rippleShader
}
@@ -124,6 +125,13 @@
rippleShader.rippleFill = rippleFill
}
+ /**
+ * Set the intensity of the sparkles.
+ */
+ fun setSparkleStrength(strength: Float) {
+ rippleShader.sparkleStrength = strength
+ }
+
override fun onDraw(canvas: Canvas?) {
if (canvas == null || !canvas.isHardwareAccelerated) {
// Drawing with the ripple shader requires hardware acceleration, so skip
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl b/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl
new file mode 100644
index 0000000..f7c4dad
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+/** Interface implemented by ScreenshotProxyService */
+interface IScreenshotProxy {
+
+ /** Is the notification shade currently exanded? */
+ boolean isNotificationShadeExpanded();
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCapture.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCapture.kt
index 39f35a5..7779760 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCapture.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCapture.kt
@@ -22,5 +22,5 @@
fun captureDisplay(displayId: Int, crop: Rect? = null): Bitmap?
- fun captureTask(taskId: Int): Bitmap?
+ suspend fun captureTask(taskId: Int): Bitmap?
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
index 258c436..246265b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
@@ -27,13 +27,19 @@
import android.view.SurfaceControl.DisplayCaptureArgs
import android.view.SurfaceControl.ScreenshotHardwareBuffer
import androidx.annotation.VisibleForTesting
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
private const val TAG = "ImageCaptureImpl"
+@SysUISingleton
open class ImageCaptureImpl @Inject constructor(
private val displayManager: DisplayManager,
- private val atmService: IActivityTaskManager
+ private val atmService: IActivityTaskManager,
+ @Background private val bgContext: CoroutineDispatcher
) : ImageCapture {
override fun captureDisplay(displayId: Int, crop: Rect?): Bitmap? {
@@ -46,8 +52,8 @@
return buffer?.asBitmap()
}
- override fun captureTask(taskId: Int): Bitmap? {
- val snapshot = atmService.takeTaskSnapshot(taskId)
+ override suspend fun captureTask(taskId: Int): Bitmap? {
+ val snapshot = withContext(bgContext) { atmService.takeTaskSnapshot(taskId) } ?: return null
return Bitmap.wrapHardwareBuffer(snapshot.hardwareBuffer, snapshot.colorSpace)
}
@@ -67,12 +73,17 @@
}
@VisibleForTesting
- open fun captureDisplay(displayToken: IBinder, width: Int, height: Int, crop: Rect): ScreenshotHardwareBuffer? {
- val captureArgs = DisplayCaptureArgs.Builder(displayToken)
- .setSize(width, height)
- .setSourceCrop(crop)
- .build()
+ open fun captureDisplay(
+ displayToken: IBinder,
+ width: Int,
+ height: Int,
+ crop: Rect
+ ): ScreenshotHardwareBuffer? {
+ val captureArgs =
+ DisplayCaptureArgs.Builder(displayToken)
+ .setSize(width, height)
+ .setSourceCrop(crop)
+ .build()
return SurfaceControl.captureDisplay(captureArgs)
}
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
index 4397d3d..a918e5d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
@@ -16,51 +16,84 @@
package com.android.systemui.screenshot
-import android.net.Uri
-import android.util.Log
-import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
+import android.graphics.Insets
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
-import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY
import java.util.function.Consumer
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
/**
* Processes a screenshot request sent from {@link ScreenshotHelper}.
*/
@SysUISingleton
-internal class RequestProcessor @Inject constructor(
- private val controller: ScreenshotController,
+class RequestProcessor @Inject constructor(
+ private val capture: ImageCapture,
+ private val policy: ScreenshotPolicy,
+ private val flags: FeatureFlags,
+ /** For the Java Async version, to invoke the callback. */
+ @Application private val mainScope: CoroutineScope
) {
- fun processRequest(
- request: ScreenshotRequest,
- onSavedListener: Consumer<Uri>,
- callback: RequestCallback
- ) {
+ /**
+ * Inspects the incoming request, returning a potentially modified request depending on policy.
+ *
+ * @param request the request to process
+ */
+ suspend fun process(request: ScreenshotRequest): ScreenshotRequest {
+ var result = request
- if (request.type == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
- val image = HardwareBitmapBundler.bundleToHardwareBitmap(request.bitmapBundle)
+ // Apply work profile screenshots policy:
+ //
+ // If the focused app belongs to a work profile, transforms a full screen
+ // (or partial) screenshot request to a task snapshot (provided image) screenshot.
- controller.handleImageAsScreenshot(
- image, request.boundsInScreen, request.insets,
- request.taskId, request.userId, request.topComponent, onSavedListener, callback
- )
- return
+ // Whenever displayContentInfo is fetched, the topComponent is also populated
+ // regardless of the managed profile status.
+
+ if (request.type != TAKE_SCREENSHOT_PROVIDED_IMAGE &&
+ flags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
+ ) {
+
+ val info = policy.findPrimaryContent(policy.getDefaultDisplayId())
+
+ result = if (policy.isManagedProfile(info.userId)) {
+ val image = capture.captureTask(info.taskId)
+ ?: error("Task snapshot returned a null Bitmap!")
+
+ // Provide the task snapshot as the screenshot
+ ScreenshotRequest(
+ TAKE_SCREENSHOT_PROVIDED_IMAGE, request.source,
+ HardwareBitmapBundler.hardwareBitmapToBundle(image),
+ info.bounds, Insets.NONE, info.taskId, info.userId, info.component
+ )
+ } else {
+ // Create a new request of the same type which includes the top component
+ ScreenshotRequest(request.source, request.type, info.component)
+ }
}
- when (request.type) {
- TAKE_SCREENSHOT_FULLSCREEN ->
- controller.takeScreenshotFullscreen(null, onSavedListener, callback)
- TAKE_SCREENSHOT_SELECTED_REGION ->
- controller.takeScreenshotPartial(null, onSavedListener, callback)
- else -> Log.w(TAG, "Invalid screenshot option: ${request.type}")
- }
+ return result
}
- companion object {
- const val TAG: String = "RequestProcessor"
+ /**
+ * Note: This is for compatibility with existing Java. Prefer the suspending function when
+ * calling from a Coroutine context.
+ *
+ * @param request the request to process
+ * @param callback the callback to provide the processed request, invoked from the main thread
+ */
+ fun processAsync(request: ScreenshotRequest, callback: Consumer<ScreenshotRequest>) {
+ mainScope.launch {
+ val result = process(request)
+ callback.accept(result)
+ }
}
}
+
+private const val TAG = "RequestProcessor"
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
new file mode 100644
index 0000000..3580010
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.annotation.UserIdInt
+import android.content.ComponentName
+import android.graphics.Rect
+import android.view.Display
+
+/**
+ * Provides policy decision-making information to screenshot request handling.
+ */
+interface ScreenshotPolicy {
+
+ /** @return true if the user is a managed profile (a.k.a. work profile) */
+ suspend fun isManagedProfile(@UserIdInt userId: Int): Boolean
+
+ /**
+ * Requests information about the owner of display content which occupies a majority of the
+ * screenshot and/or has most recently been interacted with at the time the screenshot was
+ * requested.
+ *
+ * @param displayId the id of the display to inspect
+ * @return content info for the primary content on the display
+ */
+ suspend fun findPrimaryContent(displayId: Int): DisplayContentInfo
+
+ data class DisplayContentInfo(
+ val component: ComponentName,
+ val bounds: Rect,
+ @UserIdInt val userId: Int,
+ val taskId: Int,
+ )
+
+ fun getDefaultDisplayId(): Int = Display.DEFAULT_DISPLAY
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
new file mode 100644
index 0000000..ba809f6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.annotation.UserIdInt
+import android.app.ActivityTaskManager
+import android.app.ActivityTaskManager.RootTaskInfo
+import android.app.IActivityTaskManager
+import android.app.WindowConfiguration
+import android.app.WindowConfiguration.activityTypeToString
+import android.app.WindowConfiguration.windowingModeToString
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.graphics.Rect
+import android.os.Process
+import android.os.RemoteException
+import android.os.UserManager
+import android.util.Log
+import android.view.Display.DEFAULT_DISPLAY
+import com.android.internal.infra.ServiceConnector
+import com.android.systemui.SystemUIService
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
+import java.util.Arrays
+import javax.inject.Inject
+import kotlin.coroutines.resume
+import kotlin.coroutines.suspendCoroutine
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+
+@SysUISingleton
+internal class ScreenshotPolicyImpl @Inject constructor(
+ context: Context,
+ private val userMgr: UserManager,
+ private val atmService: IActivityTaskManager,
+ @Background val bgDispatcher: CoroutineDispatcher,
+) : ScreenshotPolicy {
+
+ private val systemUiContent =
+ DisplayContentInfo(
+ ComponentName(context, SystemUIService::class.java),
+ Rect(),
+ ActivityTaskManager.INVALID_TASK_ID,
+ Process.myUserHandle().identifier,
+ )
+
+ private val proxyConnector: ServiceConnector<IScreenshotProxy> =
+ ServiceConnector.Impl(
+ context,
+ Intent(context, ScreenshotProxyService::class.java),
+ Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
+ context.userId,
+ IScreenshotProxy.Stub::asInterface
+ )
+
+ override fun getDefaultDisplayId(): Int {
+ return DEFAULT_DISPLAY
+ }
+
+ override suspend fun isManagedProfile(@UserIdInt userId: Int): Boolean {
+ return withContext(bgDispatcher) { userMgr.isManagedProfile(userId) }
+ }
+
+ private fun nonPipVisibleTask(info: RootTaskInfo): Boolean {
+ return info.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED &&
+ info.isVisible &&
+ info.isRunning &&
+ info.numActivities > 0 &&
+ info.topActivity != null &&
+ info.childTaskIds.isNotEmpty()
+ }
+
+ /**
+ * Uses RootTaskInfo from ActivityTaskManager to guess at the primary focused task within a
+ * display. If no task is visible or the top task is covered by a system window, the info
+ * reported will reference a SystemUI component instead.
+ */
+ override suspend fun findPrimaryContent(displayId: Int): DisplayContentInfo {
+ // Determine if the notification shade is expanded. If so, task windows are not
+ // visible behind it, so the screenshot should instead be associated with SystemUI.
+ if (isNotificationShadeExpanded()) {
+ return systemUiContent
+ }
+
+ val taskInfoList = getAllRootTaskInfosOnDisplay(displayId)
+ if (DEBUG) {
+ debugLogRootTaskInfos(taskInfoList)
+ }
+
+ // If no visible task is located, then report SystemUI as the foreground content
+ val target = taskInfoList.firstOrNull(::nonPipVisibleTask) ?: return systemUiContent
+
+ val topActivity: ComponentName = target.topActivity ?: error("should not be null")
+ val topChildTask = target.childTaskIds.size - 1
+ val childTaskId = target.childTaskIds[topChildTask]
+ val childTaskUserId = target.childTaskUserIds[topChildTask]
+ val childTaskBounds = target.childTaskBounds[topChildTask]
+
+ return DisplayContentInfo(topActivity, childTaskBounds, childTaskId, childTaskUserId)
+ }
+
+ private fun debugLogRootTaskInfos(taskInfoList: List<RootTaskInfo>) {
+ for (info in taskInfoList) {
+ Log.d(
+ TAG,
+ "[root task info] " +
+ "taskId=${info.taskId} " +
+ "parentTaskId=${info.parentTaskId} " +
+ "position=${info.position} " +
+ "positionInParent=${info.positionInParent} " +
+ "isVisible=${info.isVisible()} " +
+ "visible=${info.visible} " +
+ "isFocused=${info.isFocused} " +
+ "isSleeping=${info.isSleeping} " +
+ "isRunning=${info.isRunning} " +
+ "windowMode=${windowingModeToString(info.windowingMode)} " +
+ "activityType=${activityTypeToString(info.activityType)} " +
+ "topActivity=${info.topActivity} " +
+ "topActivityInfo=${info.topActivityInfo} " +
+ "numActivities=${info.numActivities} " +
+ "childTaskIds=${Arrays.toString(info.childTaskIds)} " +
+ "childUserIds=${Arrays.toString(info.childTaskUserIds)} " +
+ "childTaskBounds=${Arrays.toString(info.childTaskBounds)} " +
+ "childTaskNames=${Arrays.toString(info.childTaskNames)}"
+ )
+
+ for (j in 0 until info.childTaskIds.size) {
+ Log.d(TAG, " *** [$j] ******")
+ Log.d(TAG, " *** childTaskIds[$j]: ${info.childTaskIds[j]}")
+ Log.d(TAG, " *** childTaskUserIds[$j]: ${info.childTaskUserIds[j]}")
+ Log.d(TAG, " *** childTaskBounds[$j]: ${info.childTaskBounds[j]}")
+ Log.d(TAG, " *** childTaskNames[$j]: ${info.childTaskNames[j]}")
+ }
+ }
+ }
+
+ private suspend fun getAllRootTaskInfosOnDisplay(displayId: Int): List<RootTaskInfo> =
+ withContext(bgDispatcher) {
+ try {
+ atmService.getAllRootTaskInfosOnDisplay(displayId)
+ } catch (e: RemoteException) {
+ Log.e(TAG, "getAllRootTaskInfosOnDisplay", e)
+ listOf()
+ }
+ }
+
+ private suspend fun isNotificationShadeExpanded(): Boolean = suspendCoroutine { k ->
+ proxyConnector
+ .postForResult { it.isNotificationShadeExpanded }
+ .whenComplete { expanded, error ->
+ if (error != null) {
+ Log.e(TAG, "isNotificationShadeExpanded", error)
+ }
+ k.resume(expanded ?: false)
+ }
+ }
+
+ companion object {
+ const val TAG: String = "ScreenshotPolicyImpl"
+ const val DEBUG: Boolean = false
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
new file mode 100644
index 0000000..9654e03
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.screenshot
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import android.util.Log
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import javax.inject.Inject
+
+/**
+ * Provides state from the main SystemUI process on behalf of the Screenshot process.
+ */
+internal class ScreenshotProxyService @Inject constructor(
+ private val mExpansionMgr: PanelExpansionStateManager
+) : Service() {
+
+ private val mBinder: IBinder = object : IScreenshotProxy.Stub() {
+ /**
+ * @return true when the notification shade is partially or fully expanded.
+ */
+ override fun isNotificationShadeExpanded(): Boolean {
+ val expanded = !mExpansionMgr.isClosed()
+ Log.d(TAG, "isNotificationShadeExpanded(): $expanded")
+ return expanded
+ }
+ }
+
+ override fun onBind(intent: Intent): IBinder? {
+ Log.d(TAG, "onBind: $intent")
+ return mBinder
+ }
+
+ companion object {
+ const val TAG = "ScreenshotProxyService"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 7bf3217..8b37aab 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -22,6 +22,7 @@
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_PROCESS_COMPLETE;
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_URI;
import static com.android.systemui.flags.Flags.SCREENSHOT_REQUEST_PROCESSOR;
+import static com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
import static com.android.systemui.screenshot.LogConfig.DEBUG_SERVICE;
@@ -69,7 +70,7 @@
public class TakeScreenshotService extends Service {
private static final String TAG = logTag(TakeScreenshotService.class);
- private ScreenshotController mScreenshot;
+ private final ScreenshotController mScreenshot;
private final UserManager mUserManager;
private final DevicePolicyManager mDevicePolicyManager;
@@ -97,7 +98,7 @@
};
/** Informs about coarse grained state of the Controller. */
- interface RequestCallback {
+ public interface RequestCallback {
/** Respond to the current request indicating the screenshot request failed. */
void reportError();
@@ -124,6 +125,7 @@
mBgExecutor = bgExecutor;
mFeatureFlags = featureFlags;
mFeatureFlags.addListener(SCREENSHOT_REQUEST_PROCESSOR, FlagEvent::requestNoRestart);
+ mFeatureFlags.addListener(SCREENSHOT_WORK_PROFILE_POLICY, FlagEvent::requestNoRestart);
mProcessor = processor;
}
@@ -150,10 +152,7 @@
if (DEBUG_SERVICE) {
Log.d(TAG, "onUnbind");
}
- if (mScreenshot != null) {
- mScreenshot.removeWindow();
- mScreenshot = null;
- }
+ mScreenshot.removeWindow();
unregisterReceiver(mCloseSystemDialogs);
return false;
}
@@ -161,10 +160,7 @@
@Override
public void onDestroy() {
super.onDestroy();
- if (mScreenshot != null) {
- mScreenshot.onDestroy();
- mScreenshot = null;
- }
+ mScreenshot.onDestroy();
if (DEBUG_SERVICE) {
Log.d(TAG, "onDestroy");
}
@@ -229,49 +225,57 @@
if (mFeatureFlags.isEnabled(SCREENSHOT_REQUEST_PROCESSOR)) {
Log.d(TAG, "handleMessage: Using request processor");
- mProcessor.processRequest(screenshotRequest, uriConsumer, requestCallback);
+ mProcessor.processAsync(screenshotRequest,
+ (request) -> dispatchToController(request, uriConsumer, requestCallback));
return true;
}
- switch (screenshotRequest.getType()) {
+ dispatchToController(screenshotRequest, uriConsumer, requestCallback);
+ return true;
+ }
+
+ private void dispatchToController(ScreenshotHelper.ScreenshotRequest request,
+ Consumer<Uri> uriConsumer, RequestCallback callback) {
+
+ ComponentName topComponent = request.getTopComponent();
+
+ switch (request.getType()) {
case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_FULLSCREEN");
}
- mScreenshot.takeScreenshotFullscreen(topComponent, uriConsumer, requestCallback);
+ mScreenshot.takeScreenshotFullscreen(topComponent, uriConsumer, callback);
break;
case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_SELECTED_REGION");
}
- mScreenshot.takeScreenshotPartial(topComponent, uriConsumer, requestCallback);
+ mScreenshot.takeScreenshotPartial(topComponent, uriConsumer, callback);
break;
case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_PROVIDED_IMAGE");
}
Bitmap screenshot = ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap(
- screenshotRequest.getBitmapBundle());
- Rect screenBounds = screenshotRequest.getBoundsInScreen();
- Insets insets = screenshotRequest.getInsets();
- int taskId = screenshotRequest.getTaskId();
- int userId = screenshotRequest.getUserId();
+ request.getBitmapBundle());
+ Rect screenBounds = request.getBoundsInScreen();
+ Insets insets = request.getInsets();
+ int taskId = request.getTaskId();
+ int userId = request.getUserId();
if (screenshot == null) {
Log.e(TAG, "Got null bitmap from screenshot message");
mNotificationsController.notifyScreenshotError(
R.string.screenshot_failed_to_capture_text);
- requestCallback.reportError();
+ callback.reportError();
} else {
mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
- taskId, userId, topComponent, uriConsumer, requestCallback);
+ taskId, userId, topComponent, uriConsumer, callback);
}
break;
default:
- Log.w(TAG, "Invalid screenshot option: " + msg.what);
- return false;
+ Log.w(TAG, "Invalid screenshot option: " + request.getType());
}
- return true;
}
private static void sendComplete(Messenger target) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
index 3e442587..fdb0100 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,9 @@
import com.android.systemui.screenshot.ImageCapture;
import com.android.systemui.screenshot.ImageCaptureImpl;
+import com.android.systemui.screenshot.ScreenshotPolicy;
+import com.android.systemui.screenshot.ScreenshotPolicyImpl;
+import com.android.systemui.screenshot.ScreenshotProxyService;
import com.android.systemui.screenshot.TakeScreenshotService;
import dagger.Binds;
@@ -33,12 +36,20 @@
@Module
public abstract class ScreenshotModule {
- /** */
@Binds
@IntoMap
@ClassKey(TakeScreenshotService.class)
- public abstract Service bindTakeScreenshotService(TakeScreenshotService service);
+ abstract Service bindTakeScreenshotService(TakeScreenshotService service);
@Binds
- public abstract ImageCapture bindImageCapture(ImageCaptureImpl capture);
+ @IntoMap
+ @ClassKey(ScreenshotProxyService.class)
+ abstract Service bindScreenshotProxyService(ScreenshotProxyService service);
+
+ @Binds
+ abstract ScreenshotPolicy bindScreenshotPolicyImpl(ScreenshotPolicyImpl impl);
+
+ @Binds
+ abstract ImageCapture bindImageCaptureImpl(ImageCaptureImpl capture);
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotifPanelEvents.kt b/packages/SystemUI/src/com/android/systemui/shade/NotifPanelEvents.kt
index ce9d89f..4558061 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotifPanelEvents.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotifPanelEvents.kt
@@ -29,11 +29,25 @@
interface Listener {
/** Invoked when the notification panel starts or stops collapsing. */
- fun onPanelCollapsingChanged(isCollapsing: Boolean)
+ @JvmDefault
+ fun onPanelCollapsingChanged(isCollapsing: Boolean) {}
/**
* Invoked when the notification panel starts or stops launching an [android.app.Activity].
*/
- fun onLaunchingActivityChanged(isLaunchingActivity: Boolean)
+ @JvmDefault
+ fun onLaunchingActivityChanged(isLaunchingActivity: Boolean) {}
+
+ /**
+ * Invoked when the "expand immediate" attribute changes.
+ *
+ * An example of expanding immediately is when swiping down from the top with two fingers.
+ * Instead of going to QQS, we immediately expand to full QS.
+ *
+ * Another example is when full QS is showing, and we swipe up from the bottom. Instead of
+ * going to QQS, the panel fully collapses.
+ */
+ @JvmDefault
+ fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index a353e8f..e6d10228 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -54,7 +54,6 @@
import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.PixelFormat;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
@@ -98,6 +97,7 @@
import com.android.internal.policy.SystemBarUtils;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.ActiveUnlockConfig;
+import com.android.keyguard.KeyguardClockSwitch.ClockSize;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardStatusViewController;
import com.android.keyguard.KeyguardUnfoldTransition;
@@ -447,7 +447,6 @@
*/
private boolean mQsAnimatorExpand;
private boolean mIsLaunchTransitionFinished;
- private boolean mOnlyAffordanceInThisMotion;
private ValueAnimator mQsSizeChangeAnimator;
private boolean mQsScrimEnabled = true;
@@ -725,6 +724,7 @@
AccessibilityManager accessibilityManager, @DisplayId int displayId,
KeyguardUpdateMonitor keyguardUpdateMonitor,
MetricsLogger metricsLogger,
+ ShadeLogger shadeLogger,
ConfigurationController configurationController,
Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
@@ -791,6 +791,7 @@
panelExpansionStateManager,
ambientState,
interactionJankMonitor,
+ shadeLogger,
systemClock);
mView = view;
mVibratorHelper = vibratorHelper;
@@ -1427,19 +1428,10 @@
private void updateClockAppearance() {
int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
- final boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
- .getVisibleNotificationCount() != 0
- || mMediaDataManager.hasActiveMediaOrRecommendation();
- boolean splitShadeWithActiveMedia =
- mSplitShadeEnabled && mMediaDataManager.hasActiveMediaOrRecommendation();
boolean shouldAnimateClockChange = mScreenOffAnimationController.shouldAnimateClockChange();
- if ((hasVisibleNotifications && !mSplitShadeEnabled)
- || (splitShadeWithActiveMedia && !mDozing)) {
- mKeyguardStatusViewController.displayClock(SMALL, shouldAnimateClockChange);
- } else {
- mKeyguardStatusViewController.displayClock(LARGE, shouldAnimateClockChange);
- }
- updateKeyguardStatusViewAlignment(true /* animate */);
+ mKeyguardStatusViewController.displayClock(computeDesiredClockSize(),
+ shouldAnimateClockChange);
+ updateKeyguardStatusViewAlignment(/* animate= */true);
int userSwitcherHeight = mKeyguardQsUserSwitchController != null
? mKeyguardQsUserSwitchController.getUserIconHeight() : 0;
if (mKeyguardUserSwitcherController != null) {
@@ -1448,7 +1440,7 @@
float expandedFraction =
mScreenOffAnimationController.shouldExpandNotifications()
? 1.0f : getExpandedFraction();
- float darkamount =
+ float darkAmount =
mScreenOffAnimationController.shouldExpandNotifications()
? 1.0f : mInterpolatedDarkAmount;
@@ -1466,7 +1458,7 @@
mKeyguardStatusViewController.getLockscreenHeight(),
userSwitcherHeight,
userSwitcherPreferredY,
- darkamount, mOverStretchAmount,
+ darkAmount, mOverStretchAmount,
bypassEnabled, getUnlockedStackScrollerPadding(),
computeQsExpansionFraction(),
mDisplayTopInset,
@@ -1498,6 +1490,34 @@
updateClock();
}
+ @ClockSize
+ private int computeDesiredClockSize() {
+ if (mSplitShadeEnabled) {
+ return computeDesiredClockSizeForSplitShade();
+ }
+ return computeDesiredClockSizeForSingleShade();
+ }
+
+ @ClockSize
+ private int computeDesiredClockSizeForSingleShade() {
+ if (hasVisibleNotifications()) {
+ return SMALL;
+ }
+ return LARGE;
+ }
+
+ @ClockSize
+ private int computeDesiredClockSizeForSplitShade() {
+ // Media is not visible to the user on AOD.
+ boolean isMediaVisibleToUser =
+ mMediaDataManager.hasActiveMediaOrRecommendation() && !isOnAod();
+ if (isMediaVisibleToUser) {
+ // When media is visible, it overlaps with the large clock. Use small clock instead.
+ return SMALL;
+ }
+ return LARGE;
+ }
+
private void updateKeyguardStatusViewAlignment(boolean animate) {
boolean shouldBeCentered = shouldKeyguardStatusViewBeCentered();
if (mStatusViewCentered != shouldBeCentered) {
@@ -1524,12 +1544,35 @@
}
private boolean shouldKeyguardStatusViewBeCentered() {
- boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
+ if (mSplitShadeEnabled) {
+ return shouldKeyguardStatusViewBeCenteredInSplitShade();
+ }
+ return true;
+ }
+
+ private boolean shouldKeyguardStatusViewBeCenteredInSplitShade() {
+ if (!hasVisibleNotifications()) {
+ // No notifications visible. It is safe to have the clock centered as there will be no
+ // overlap.
+ return true;
+ }
+ if (hasPulsingNotifications()) {
+ // Pulsing notification appears on the right. Move clock left to avoid overlap.
+ return false;
+ }
+ // "Visible" notifications are actually not visible on AOD (unless pulsing), so it is safe
+ // to center the clock without overlap.
+ return isOnAod();
+ }
+
+ private boolean isOnAod() {
+ return mDozing && mDozeParameters.getAlwaysOn();
+ }
+
+ private boolean hasVisibleNotifications() {
+ return mNotificationStackScrollLayoutController
.getVisibleNotificationCount() != 0
|| mMediaDataManager.hasActiveMediaOrRecommendation();
- boolean isOnAod = mDozing && mDozeParameters.getAlwaysOn();
- return !mSplitShadeEnabled || !hasVisibleNotifications || isOnAod
- || hasPulsingNotifications();
}
/**
@@ -1702,12 +1745,17 @@
}
if (mQsExpanded) {
- mQsExpandImmediate = true;
+ setQsExpandImmediate(true);
setShowShelfOnly(true);
}
super.collapse(delayed, speedUpFactor);
}
+ private void setQsExpandImmediate(boolean expandImmediate) {
+ mQsExpandImmediate = expandImmediate;
+ mPanelEventsEmitter.notifyExpandImmediateChange(expandImmediate);
+ }
+
private void setShowShelfOnly(boolean shelfOnly) {
mNotificationStackScrollLayoutController.setShouldShowShelfOnly(
shelfOnly && !mSplitShadeEnabled);
@@ -1760,7 +1808,7 @@
public void expandWithQs() {
if (isQsExpansionEnabled()) {
- mQsExpandImmediate = true;
+ setQsExpandImmediate(true);
setShowShelfOnly(true);
}
if (mSplitShadeEnabled && isOnKeyguard()) {
@@ -1839,6 +1887,8 @@
}
if (mQsExpansionAnimator != null) {
mInitialHeightOnTouch = mQsExpansionHeight;
+ mShadeLog.logMotionEvent(event,
+ "onQsIntercept: down action, QS tracking enabled");
mQsTracking = true;
traceQsJank(true /* startTracing */, false /* wasCancelled */);
mNotificationStackScrollLayoutController.cancelLongPress();
@@ -1866,12 +1916,16 @@
setQsExpansion(h + mInitialHeightOnTouch);
trackMovement(event);
return true;
+ } else {
+ mShadeLog.logMotionEvent(event,
+ "onQsIntercept: move ignored because qs tracking disabled");
}
if ((h > getTouchSlop(event) || (h < -getTouchSlop(event) && mQsExpanded))
&& Math.abs(h) > Math.abs(x - mInitialTouchX)
&& shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) {
if (DEBUG_LOGCAT) Log.d(TAG, "onQsIntercept - start tracking expansion");
mView.getParent().requestDisallowInterceptTouchEvent(true);
+ mShadeLog.onQsInterceptMoveQsTrackingEnabled(h);
mQsTracking = true;
traceQsJank(true /* startTracing */, false /* wasCancelled */);
onQsExpansionStarted();
@@ -1887,6 +1941,7 @@
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
trackMovement(event);
+ mShadeLog.logMotionEvent(event, "onQsIntercept: up action, QS tracking disabled");
mQsTracking = false;
break;
}
@@ -1924,7 +1979,6 @@
private void initDownStates(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mOnlyAffordanceInThisMotion = false;
mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
mDozingOnDown = isDozing();
mDownX = event.getX();
@@ -2063,6 +2117,7 @@
&& collapsedQs && isQsExpansionEnabled();
if (action == MotionEvent.ACTION_DOWN && expandedShadeCollapsedQs) {
// Down in the empty area while fully expanded - go to QS.
+ mShadeLog.logMotionEvent(event, "handleQsTouch: down action, QS tracking enabled");
mQsTracking = true;
traceQsJank(true /* startTracing */, false /* wasCancelled */);
mConflictingQsExpansionGesture = true;
@@ -2077,6 +2132,8 @@
if (!mQsExpandImmediate && mQsTracking) {
onQsTouch(event);
if (!mConflictingQsExpansionGesture && !mSplitShadeEnabled) {
+ mShadeLog.logMotionEvent(event,
+ "handleQsTouch: not immediate expand or conflicting gesture");
return true;
}
}
@@ -2089,7 +2146,7 @@
if (mTwoFingerQsExpandPossible && isOpenQsEvent(event) && event.getY(event.getActionIndex())
< mStatusBarMinHeight) {
mMetricsLogger.count(COUNTER_PANEL_OPEN_QS, 1);
- mQsExpandImmediate = true;
+ setQsExpandImmediate(true);
setShowShelfOnly(true);
requestPanelHeightUpdate();
@@ -2144,6 +2201,7 @@
event.getX(), event.getY(), -1)) {
if (DEBUG_LOGCAT) Log.d(TAG, "handleQsDown");
mFalsingCollector.onQsDown();
+ mShadeLog.logMotionEvent(event, "handleQsDown: down action, QS tracking enabled");
mQsTracking = true;
onQsExpansionStarted();
mInitialHeightOnTouch = mQsExpansionHeight;
@@ -2226,6 +2284,7 @@
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
+ mShadeLog.logMotionEvent(event, "onQsTouch: down action, QS tracking enabled");
mQsTracking = true;
traceQsJank(true /* startTracing */, false /* wasCancelled */);
mInitialTouchY = y;
@@ -2252,6 +2311,7 @@
case MotionEvent.ACTION_MOVE:
if (DEBUG_LOGCAT) Log.d(TAG, "onQSTouch move");
+ mShadeLog.logMotionEvent(event, "onQsTouch: move action, setting QS expansion");
setQsExpansion(h + mInitialHeightOnTouch);
if (h >= getFalsingThreshold()) {
mQsTouchAboveFalsingThreshold = true;
@@ -2261,6 +2321,8 @@
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ mShadeLog.logMotionEvent(event,
+ "onQsTouch: up/cancel action, QS tracking disabled");
mQsTracking = false;
mTrackingPointer = -1;
trackMovement(event);
@@ -3083,8 +3145,8 @@
positionClockAndNotifications();
}
}
- if (mQsExpandImmediate || mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
- && !mQsExpansionFromOverscroll) {
+ if (mQsExpandImmediate || (mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
+ && !mQsExpansionFromOverscroll)) {
float t;
if (mKeyguardShowing) {
@@ -3291,7 +3353,7 @@
} else {
setListening(true);
}
- mQsExpandImmediate = false;
+ setQsExpandImmediate(false);
setShowShelfOnly(false);
mTwoFingerQsExpandPossible = false;
updateTrackingHeadsUp(null);
@@ -3349,7 +3411,7 @@
super.onTrackingStarted();
mScrimController.onTrackingStarted();
if (mQsFullyExpanded) {
- mQsExpandImmediate = true;
+ setQsExpandImmediate(true);
setShowShelfOnly(true);
}
mNotificationStackScrollLayoutController.onPanelTrackingStarted();
@@ -3744,13 +3806,12 @@
*
* @param dozing {@code true} when dozing.
* @param animate if transition should be animated.
- * @param wakeUpTouchLocation touch event location - if woken up by SLPI sensor.
*/
- public void setDozing(boolean dozing, boolean animate, PointF wakeUpTouchLocation) {
+ public void setDozing(boolean dozing, boolean animate) {
if (dozing == mDozing) return;
mView.setDozing(dozing);
mDozing = dozing;
- mNotificationStackScrollLayoutController.setDozing(mDozing, animate, wakeUpTouchLocation);
+ mNotificationStackScrollLayoutController.setDozing(mDozing, animate);
mKeyguardBottomArea.setDozing(mDozing, animate);
mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
mKeyguardStatusBarViewController.setDozing(mDozing);
@@ -3783,6 +3844,8 @@
mAnimateNextPositionUpdate = false;
}
mNotificationStackScrollLayoutController.setPulsing(pulsing, animatePulse);
+
+ updateKeyguardStatusViewAlignment(/* animate= */ true);
}
public void setAmbientIndicationTop(int ambientIndicationTop, boolean ambientTextVisible) {
@@ -4174,6 +4237,7 @@
|| mPulseExpansionHandler.isExpanding();
if (pulseShouldGetTouch && mPulseExpansionHandler.onTouchEvent(event)) {
// We're expanding all the other ones shouldn't get this anymore
+ mShadeLog.logMotionEvent(event, "onTouch: PulseExpansionHandler handled event");
return true;
}
if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp()
@@ -4181,14 +4245,10 @@
&& mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1);
}
- boolean handled = false;
- if (mOnlyAffordanceInThisMotion) {
- return true;
- }
- handled |= mHeadsUpTouchHelper.onTouchEvent(event);
+ boolean handled = mHeadsUpTouchHelper.onTouchEvent(event);
if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) {
- if (DEBUG_LOGCAT) Log.d(TAG, "handleQsTouch true");
+ mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event");
return true;
}
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
@@ -4679,7 +4739,7 @@
* change.
*/
public void showAodUi() {
- setDozing(true /* dozing */, false /* animate */, null);
+ setDozing(true /* dozing */, false /* animate */);
mStatusBarStateController.setUpcomingState(KEYGUARD);
mEntryManager.updateNotifications("showAodUi");
mStatusBarStateListener.onStateChanged(KEYGUARD);
@@ -4760,6 +4820,8 @@
}
} else if (!mQsExpanded && mQsExpansionAnimator == null) {
setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
+ } else {
+ mShadeLog.v("onLayoutChange: qs expansion not set");
}
updateExpandedHeight(getExpandedHeight());
updateHeader();
@@ -4914,7 +4976,7 @@
// to locked will trigger this event and we're not actually in the process of opening
// the shade, lockscreen is just always expanded
if (mSplitShadeEnabled && !isOnKeyguard()) {
- mQsExpandImmediate = true;
+ setQsExpandImmediate(true);
}
mCentralSurfaces.makeExpandedVisible(false);
}
@@ -4981,5 +5043,11 @@
cb.onPanelCollapsingChanged(isCollapsing);
}
}
+
+ private void notifyExpandImmediateChange(boolean expandImmediateEnabled) {
+ for (NotifPanelEvents.Listener cb : mListeners) {
+ cb.onExpandImmediateChanged(expandImmediateEnabled);
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java
index 4aad245..73eaa85 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java
@@ -202,6 +202,8 @@
private final InteractionJankMonitor mInteractionJankMonitor;
protected final SystemClock mSystemClock;
+ protected final ShadeLogger mShadeLog;
+
protected abstract void onExpandingFinished();
protected void onExpandingStarted() {
@@ -242,6 +244,7 @@
PanelExpansionStateManager panelExpansionStateManager,
AmbientState ambientState,
InteractionJankMonitor interactionJankMonitor,
+ ShadeLogger shadeLogger,
SystemClock systemClock) {
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
@@ -254,6 +257,7 @@
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mLockscreenGestureLogger = lockscreenGestureLogger;
mPanelExpansionStateManager = panelExpansionStateManager;
+ mShadeLog = shadeLogger;
TouchHandler touchHandler = createTouchHandler();
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
@@ -1275,9 +1279,16 @@
@Override
public boolean onTouch(View v, MotionEvent event) {
- if (mInstantExpanding || (mTouchDisabled
- && event.getActionMasked() != MotionEvent.ACTION_CANCEL) || (mMotionAborted
- && event.getActionMasked() != MotionEvent.ACTION_DOWN)) {
+ if (mInstantExpanding) {
+ mShadeLog.logMotionEvent(event, "onTouch: touch ignored due to instant expanding");
+ return false;
+ }
+ if (mTouchDisabled && event.getActionMasked() != MotionEvent.ACTION_CANCEL) {
+ mShadeLog.logMotionEvent(event, "onTouch: non-cancel action, touch disabled");
+ return false;
+ }
+ if (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
+ mShadeLog.logMotionEvent(event, "onTouch: non-down action, motion was aborted");
return false;
}
@@ -1287,6 +1298,7 @@
// Turn off tracking if it's on or the shade can get stuck in the down position.
onTrackingStopped(true /* expand */);
}
+ mShadeLog.logMotionEvent(event, "onTouch: drag not enabled");
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
new file mode 100644
index 0000000..f1e44ce
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -0,0 +1,48 @@
+package com.android.systemui.shade
+
+import android.view.MotionEvent
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogMessage
+import com.android.systemui.log.dagger.ShadeLog
+import com.google.errorprone.annotations.CompileTimeConstant
+import javax.inject.Inject
+
+private const val TAG = "systemui.shade"
+
+/** Lightweight logging utility for the Shade. */
+class ShadeLogger @Inject constructor(
+ @ShadeLog
+ private val buffer: LogBuffer
+) {
+ fun v(@CompileTimeConstant msg: String) {
+ buffer.log(TAG, LogLevel.VERBOSE, msg)
+ }
+
+ private inline fun log(
+ logLevel: LogLevel,
+ initializer: LogMessage.() -> Unit,
+ noinline printer: LogMessage.() -> String
+ ) {
+ buffer.log(TAG, logLevel, initializer, printer)
+ }
+
+ fun onQsInterceptMoveQsTrackingEnabled(h: Float) {
+ log(LogLevel.VERBOSE,
+ { double1 = h.toDouble() },
+ { "onQsIn[tercept: move action, QS tracking enabled. h = $double1" })
+ }
+
+ fun logMotionEvent(event: MotionEvent, message: String) {
+ log(LogLevel.VERBOSE, {
+ str1 = message
+ long1 = event.eventTime
+ long2 = event.downTime
+ int1 = event.action
+ int2 = event.classification
+ double1 = event.y.toDouble()
+ }, {
+ "$str1\neventTime=$long1,downTime=$long2,y=$double1,action=$int1,classification=$int2"
+ })
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 0280e0b..c04bc82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -303,11 +303,6 @@
}
@Override
- public void setDozeAmount(float dozeAmount, boolean animated) {
- setAndInstrumentDozeAmount(null, dozeAmount, animated);
- }
-
- @Override
public void setAndInstrumentDozeAmount(View view, float dozeAmount, boolean animated) {
if (mDarkAnimator != null && mDarkAnimator.isRunning()) {
if (animated && mDozeAmountTarget == dozeAmount) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
index 2b31901..2cc7738 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
@@ -99,14 +99,6 @@
boolean setIsDozing(boolean isDozing);
/**
- * Changes the current doze amount.
- *
- * @param dozeAmount New doze/dark amount.
- * @param animated If change should be animated or not. This will cancel current animations.
- */
- void setDozeAmount(float dozeAmount, boolean animated);
-
- /**
* Changes the current doze amount, also starts the
* {@link com.android.internal.jank.InteractionJankMonitor InteractionJankMonitor} as possible.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 952bafb..79d883b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -42,7 +42,6 @@
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Path;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.provider.Settings;
@@ -4405,8 +4404,7 @@
* See {@link AmbientState#setDozing}.
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setDozing(boolean dozing, boolean animate,
- @Nullable PointF touchWakeUpScreenLocation) {
+ public void setDozing(boolean dozing, boolean animate) {
if (mAmbientState.isDozing() == dozing) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 9998fe4..3f6586c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -33,7 +33,6 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
-import android.graphics.PointF;
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
@@ -1235,8 +1234,8 @@
mView.setAnimationsEnabled(enabled);
}
- public void setDozing(boolean dozing, boolean animate, PointF wakeUpTouchLocation) {
- mView.setDozing(dozing, animate, wakeUpTouchLocation);
+ public void setDozing(boolean dozing, boolean animate) {
+ mView.setDozing(dozing, animate);
}
public void setPulsing(boolean pulsing, boolean animatePulse) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 65ba5ad..e754d5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -512,7 +512,8 @@
Trace.beginSection("MODE_WAKE_AND_UNLOCK");
} else {
Trace.beginSection("MODE_WAKE_AND_UNLOCK_FROM_DREAM");
- mUpdateMonitor.awakenFromDream();
+ // Don't call awaken from Dream here. In order to avoid flickering, wait until
+ // later to awaken.
}
mNotificationShadeWindowController.setNotificationShadeFocusable(false);
mKeyguardViewMediator.onWakeAndUnlocking();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 7da1d6c..08b1c19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -68,7 +68,6 @@
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.graphics.Point;
-import android.graphics.PointF;
import android.hardware.devicestate.DeviceStateManager;
import android.metrics.LogMaker;
import android.net.Uri;
@@ -462,7 +461,6 @@
@VisibleForTesting
DozeServiceHost mDozeServiceHost;
private boolean mWakeUpComingFromTouch;
- private PointF mWakeUpTouchLocation;
private LightRevealScrim mLightRevealScrim;
private PowerButtonReveal mPowerButtonReveal;
@@ -619,8 +617,6 @@
private int mLastCameraLaunchSource;
protected PowerManager.WakeLock mGestureWakeLock;
- private final int[] mTmpInt2 = new int[2];
-
// Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
private int mLastLoggedStateFingerprint;
private boolean mIsLaunchingActivityOverLockscreen;
@@ -1446,16 +1442,6 @@
mPowerManager.wakeUp(
time, PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:" + why);
mWakeUpComingFromTouch = true;
-
- // NOTE, the incoming view can sometimes be the entire container... unsure if
- // this location is valuable enough
- if (where != null) {
- where.getLocationInWindow(mTmpInt2);
- mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
- mTmpInt2[1] + where.getHeight() / 2);
- } else {
- mWakeUpTouchLocation = new PointF(-1, -1);
- }
mFalsingCollector.onScreenOnFromTouch();
}
}
@@ -1972,7 +1958,6 @@
PowerManager.WAKE_REASON_APPLICATION,
"com.android.systemui:full_screen_intent");
mWakeUpComingFromTouch = false;
- mWakeUpTouchLocation = null;
}
}
@@ -3242,7 +3227,7 @@
|| (mDozing && mDozeParameters.shouldControlScreenOff()
&& visibleNotOccludedOrWillBe);
- mNotificationPanelViewController.setDozing(mDozing, animate, mWakeUpTouchLocation);
+ mNotificationPanelViewController.setDozing(mDozing, animate);
updateQsExpansionEnabled();
Trace.endSection();
}
@@ -3573,7 +3558,6 @@
mLaunchCameraWhenFinishedWaking = false;
mDeviceInteractive = false;
mWakeUpComingFromTouch = false;
- mWakeUpTouchLocation = null;
updateVisibleToUser();
updateNotificationPanelTouchState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index d058b75..53e08ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -10,6 +10,7 @@
import android.provider.Settings
import android.view.Surface
import android.view.View
+import android.view.WindowManager.fixScale
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF
import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
@@ -138,8 +139,8 @@
}
fun updateAnimatorDurationScale() {
- animatorDurationScale =
- globalSettings.getFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 1f)
+ animatorDurationScale = fixScale(
+ globalSettings.getFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 1f))
}
override fun shouldDelayKeyguardShow(): Boolean =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoCollector.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoCollector.kt
deleted file mode 100644
index 6c02b0d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoCollector.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline
-
-import com.android.systemui.statusbar.pipeline.repository.NetworkCapabilityInfo
-import kotlinx.coroutines.flow.StateFlow
-
-/**
- * Interface exposing a flow for raw connectivity information. Clients should collect on
- * [rawConnectivityInfoFlow] to get updates on connectivity information.
- *
- * Note: [rawConnectivityInfoFlow] should be a *hot* flow, so that we only create one instance of it
- * and all clients get references to the same flow.
- *
- * This will be used for the new status bar pipeline to compile information we need to display some
- * of the icons in the RHS of the status bar.
- */
-interface ConnectivityInfoCollector {
- val rawConnectivityInfoFlow: StateFlow<RawConnectivityInfo>
-}
-
-/**
- * An object containing all of the raw connectivity information.
- *
- * Importantly, all the information in this object should not be processed at all (i.e., the data
- * that we receive from callbacks should be piped straight into this object and not be filtered,
- * manipulated, or processed in any way). Instead, any listeners on
- * [ConnectivityInfoCollector.rawConnectivityInfoFlow] can do the processing.
- *
- * This allows us to keep all the processing in one place which is beneficial for logging and
- * debugging purposes.
- */
-data class RawConnectivityInfo(
- val networkCapabilityInfo: Map<Int, NetworkCapabilityInfo> = emptyMap(),
-)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoCollectorImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoCollectorImpl.kt
deleted file mode 100644
index 8d69422..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoCollectorImpl.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.statusbar.pipeline.repository.NetworkCapabilitiesRepo
-import kotlinx.coroutines.CoroutineScope
-import javax.inject.Inject
-import kotlinx.coroutines.flow.SharingStarted.Companion.Lazily
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-/**
- * The real implementation of [ConnectivityInfoCollector] that will collect information from all the
- * relevant connectivity callbacks and compile it into [rawConnectivityInfoFlow].
- */
-@SysUISingleton
-class ConnectivityInfoCollectorImpl @Inject constructor(
- networkCapabilitiesRepo: NetworkCapabilitiesRepo,
- @Application scope: CoroutineScope,
-) : ConnectivityInfoCollector {
- override val rawConnectivityInfoFlow: StateFlow<RawConnectivityInfo> =
- // TODO(b/238425913): Collect all the separate flows for individual raw information into
- // this final flow.
- networkCapabilitiesRepo.dataStream
- .map {
- RawConnectivityInfo(networkCapabilityInfo = it)
- }
- .stateIn(scope, started = Lazily, initialValue = RawConnectivityInfo())
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoProcessor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoProcessor.kt
index 1aae250..0b01816 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoProcessor.kt
@@ -20,58 +20,36 @@
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.statusbar.pipeline.repository.NetworkCapabilityInfo
+import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
import javax.inject.Inject
+import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted.Companion.Lazily
-import kotlinx.coroutines.flow.emptyFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
/**
- * A processor that transforms raw connectivity information that we get from callbacks and turns it
- * into a list of displayable connectivity information.
+ * A temporary object that collects on [WifiViewModel] flows for debugging purposes.
*
- * This will be used for the new status bar pipeline to calculate the list of icons that should be
- * displayed in the RHS of the status bar.
- *
- * Anyone can listen to [processedInfoFlow] to get updates to the processed data.
+ * This will eventually get migrated to a view binder that will use the flow outputs to set state on
+ * views. For now, this just collects on flows so that the information gets logged.
*/
@SysUISingleton
class ConnectivityInfoProcessor @Inject constructor(
- connectivityInfoCollector: ConnectivityInfoCollector,
context: Context,
+ // TODO(b/238425913): Don't use the application scope; instead, use the status bar view's
+ // scope so we only do work when there's UI that cares about it.
@Application private val scope: CoroutineScope,
- statusBarPipelineFlags: StatusBarPipelineFlags,
+ private val statusBarPipelineFlags: StatusBarPipelineFlags,
+ private val wifiViewModelProvider: Provider<WifiViewModel>,
) : CoreStartable(context) {
- // Note: This flow will not start running until a client calls `collect` on it, which means that
- // [connectivityInfoCollector]'s flow will also not start anything until that `collect` call
- // happens.
- val processedInfoFlow: Flow<ProcessedConnectivityInfo> =
- if (!statusBarPipelineFlags.isNewPipelineEnabled())
- emptyFlow()
- else connectivityInfoCollector.rawConnectivityInfoFlow
- .map { it.process() }
- .stateIn(
- scope,
- started = Lazily,
- initialValue = ProcessedConnectivityInfo()
- )
-
override fun start() {
- }
-
- private fun RawConnectivityInfo.process(): ProcessedConnectivityInfo {
- // TODO(b/238425913): Actually process the raw info into meaningful data.
- return ProcessedConnectivityInfo(this.networkCapabilityInfo)
+ if (!statusBarPipelineFlags.isNewPipelineEnabled()) {
+ return
+ }
+ // TODO(b/238425913): The view binder should do this instead. For now, do it here so we can
+ // see the logs.
+ scope.launch {
+ wifiViewModelProvider.get().isActivityInVisible.collect { }
+ }
}
}
-
-/**
- * An object containing connectivity info that has been processed into data that can be directly
- * used by the status bar (and potentially other SysUI areas) to display icons.
- */
-data class ProcessedConnectivityInfo(
- val networkCapabilityInfo: Map<Int, NetworkCapabilityInfo> = emptyMap(),
-)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityPipelineLogger.kt
deleted file mode 100644
index f88e9d6..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityPipelineLogger.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline
-
-import android.net.Network
-import android.net.NetworkCapabilities
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.dagger.StatusBarConnectivityLog
-import javax.inject.Inject
-
-@SysUISingleton
-class ConnectivityPipelineLogger @Inject constructor(
- @StatusBarConnectivityLog private val buffer: LogBuffer,
-) {
- fun logOnCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
- buffer.log(
- TAG,
- LogLevel.INFO,
- {
- int1 = network.getNetId()
- str1 = networkCapabilities.toString()
- },
- {
- "onCapabilitiesChanged: net=$int1 capabilities=$str1"
- }
- )
- }
-
- fun logOnLost(network: Network) {
- buffer.log(
- TAG,
- LogLevel.INFO,
- {
- int1 = network.getNetId()
- },
- {
- "onLost: net=$int1"
- }
- )
- }
-}
-
-private const val TAG = "SbConnectivityPipeline"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index c4e2b73..88eccb5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -17,9 +17,9 @@
package com.android.systemui.statusbar.pipeline.dagger
import com.android.systemui.CoreStartable
-import com.android.systemui.statusbar.pipeline.ConnectivityInfoCollector
-import com.android.systemui.statusbar.pipeline.ConnectivityInfoCollectorImpl
import com.android.systemui.statusbar.pipeline.ConnectivityInfoProcessor
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
@@ -34,7 +34,5 @@
abstract fun bindConnectivityInfoProcessor(cip: ConnectivityInfoProcessor): CoreStartable
@Binds
- abstract fun provideConnectivityInfoCollector(
- impl: ConnectivityInfoCollectorImpl
- ): ConnectivityInfoCollector
+ abstract fun wifiRepository(impl: WifiRepositoryImpl): WifiRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/repository/NetworkCapabilitiesRepo.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/repository/NetworkCapabilitiesRepo.kt
deleted file mode 100644
index e5980c3..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/repository/NetworkCapabilitiesRepo.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
-package com.android.systemui.statusbar.pipeline.repository
-
-import android.annotation.SuppressLint
-import android.net.ConnectivityManager
-import android.net.Network
-import android.net.NetworkCapabilities
-import android.net.NetworkRequest
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.statusbar.pipeline.ConnectivityPipelineLogger
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.SharingStarted.Companion.Lazily
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.stateIn
-
-/** Repository that contains all relevant [NetworkCapabilites] for the current networks */
-@SysUISingleton
-class NetworkCapabilitiesRepo @Inject constructor(
- connectivityManager: ConnectivityManager,
- @Application scope: CoroutineScope,
- logger: ConnectivityPipelineLogger,
-) {
- @SuppressLint("MissingPermission")
- val dataStream: StateFlow<Map<Int, NetworkCapabilityInfo>> = run {
- var state = emptyMap<Int, NetworkCapabilityInfo>()
- callbackFlow {
- val networkRequest: NetworkRequest =
- NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .build()
- val callback =
- // TODO (b/240569788): log these using [LogBuffer]
- object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
- override fun onCapabilitiesChanged(
- network: Network,
- networkCapabilities: NetworkCapabilities
- ) {
- logger.logOnCapabilitiesChanged(network, networkCapabilities)
- state =
- state.toMutableMap().also {
- it[network.getNetId()] =
- NetworkCapabilityInfo(network, networkCapabilities)
- }
- trySend(state)
- }
-
- override fun onLost(network: Network) {
- logger.logOnLost(network)
- state = state.toMutableMap().also { it.remove(network.getNetId()) }
- trySend(state)
- }
- }
- connectivityManager.registerNetworkCallback(networkRequest, callback)
-
- awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
- }
- .stateIn(scope, started = Lazily, initialValue = state)
- }
-}
-
-/** contains info about network capabilities. */
-data class NetworkCapabilityInfo(
- val network: Network,
- val capabilities: NetworkCapabilities,
-)
-
-private const val TAG = "ConnectivityRepository"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
new file mode 100644
index 0000000..2a89309
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared
+
+import android.net.Network
+import android.net.NetworkCapabilities
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.StatusBarConnectivityLog
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.toString
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.onEach
+
+@SysUISingleton
+class ConnectivityPipelineLogger @Inject constructor(
+ @StatusBarConnectivityLog private val buffer: LogBuffer,
+) {
+ /**
+ * Logs a change in one of the **raw inputs** to the connectivity pipeline.
+ */
+ fun logInputChange(callbackName: String, changeInfo: String) {
+ buffer.log(
+ SB_LOGGING_TAG,
+ LogLevel.INFO,
+ {
+ str1 = callbackName
+ str2 = changeInfo
+ },
+ {
+ "Input: $str1: $str2"
+ }
+ )
+ }
+
+ /**
+ * Logs a **data transformation** that we performed within the connectivity pipeline.
+ */
+ fun logTransformation(transformationName: String, oldValue: Any?, newValue: Any?) {
+ if (oldValue == newValue) {
+ buffer.log(
+ SB_LOGGING_TAG,
+ LogLevel.INFO,
+ {
+ str1 = transformationName
+ str2 = oldValue.toString()
+ },
+ {
+ "Transform: $str1: $str2 (transformation didn't change it)"
+ }
+ )
+ } else {
+ buffer.log(
+ SB_LOGGING_TAG,
+ LogLevel.INFO,
+ {
+ str1 = transformationName
+ str2 = oldValue.toString()
+ str3 = newValue.toString()
+ },
+ {
+ "Transform: $str1: $str2 -> $str3"
+ }
+ )
+ }
+ }
+
+ /**
+ * Logs a change in one of the **outputs** to the connectivity pipeline.
+ */
+ fun logOutputChange(outputParamName: String, changeInfo: String) {
+ buffer.log(
+ SB_LOGGING_TAG,
+ LogLevel.INFO,
+ {
+ str1 = outputParamName
+ str2 = changeInfo
+ },
+ {
+ "Output: $str1: $str2"
+ }
+ )
+ }
+
+ fun logOnCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
+ buffer.log(
+ SB_LOGGING_TAG,
+ LogLevel.INFO,
+ {
+ int1 = network.getNetId()
+ str1 = networkCapabilities.toString()
+ },
+ {
+ "onCapabilitiesChanged: net=$int1 capabilities=$str1"
+ }
+ )
+ }
+
+ fun logOnLost(network: Network) {
+ buffer.log(
+ SB_LOGGING_TAG,
+ LogLevel.INFO,
+ {
+ int1 = network.getNetId()
+ },
+ {
+ "onLost: net=$int1"
+ }
+ )
+ }
+
+ companion object {
+ const val SB_LOGGING_TAG = "SbConnectivity"
+
+ /**
+ * Log a change in one of the **outputs** to the connectivity pipeline.
+ *
+ * @param prettyPrint an optional function to transform the value into a readable string.
+ * [toString] is used if no custom function is provided.
+ */
+ fun <T : Any> Flow<T>.logOutputChange(
+ logger: ConnectivityPipelineLogger,
+ outputParamName: String,
+ prettyPrint: (T) -> String = { it.toString() }
+ ): Flow<T> {
+ return this.onEach { logger.logOutputChange(outputParamName, prettyPrint(it)) }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
new file mode 100644
index 0000000..44c0496
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.data.model
+
+/**
+ * Provides information on the current wifi activity.
+ */
+data class WifiActivityModel(
+ /** True if the wifi has activity in (download). */
+ val hasActivityIn: Boolean,
+ /** True if the wifi has activity out (upload). */
+ val hasActivityOut: Boolean,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt
new file mode 100644
index 0000000..5566fa6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.data.model
+
+/** Provides information about the current wifi network. */
+sealed class WifiNetworkModel {
+ /** A model representing that we have no active wifi network. */
+ object Inactive : WifiNetworkModel()
+
+ /** Provides information about an active wifi network. */
+ class Active(
+ /**
+ * The [android.net.Network.netId] we received from
+ * [android.net.ConnectivityManager.NetworkCallback] in association with this wifi network.
+ *
+ * Importantly, **not** [android.net.wifi.WifiInfo.getNetworkId].
+ */
+ val networkId: Int,
+
+ /** See [android.net.wifi.WifiInfo.ssid]. */
+ val ssid: String? = null,
+
+ /** See [android.net.wifi.WifiInfo.isPasspointAp]. */
+ val isPasspointAccessPoint: Boolean = false,
+
+ /** See [android.net.wifi.WifiInfo.isOsuAp]. */
+ val isOnlineSignUpForPasspointAccessPoint: Boolean = false,
+
+ /** See [android.net.wifi.WifiInfo.passpointProviderFriendlyName]. */
+ val passpointProviderFriendlyName: String? = null,
+ ) : WifiNetworkModel()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
new file mode 100644
index 0000000..43fbabc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.data.repository
+
+import android.annotation.SuppressLint
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.NetworkRequest
+import android.net.wifi.WifiInfo
+import android.net.wifi.WifiManager
+import android.net.wifi.WifiManager.TrafficStateCallback
+import android.util.Log
+import com.android.settingslib.Utils
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+
+/**
+ * Provides data related to the wifi state.
+ */
+interface WifiRepository {
+ /**
+ * Observable for the current wifi network.
+ */
+ val wifiNetwork: Flow<WifiNetworkModel>
+
+ /**
+ * Observable for the current wifi network activity.
+ */
+ val wifiActivity: Flow<WifiActivityModel>
+}
+
+/** Real implementation of [WifiRepository]. */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+@SuppressLint("MissingPermission")
+class WifiRepositoryImpl @Inject constructor(
+ connectivityManager: ConnectivityManager,
+ wifiManager: WifiManager?,
+ @Main mainExecutor: Executor,
+ logger: ConnectivityPipelineLogger,
+) : WifiRepository {
+ override val wifiNetwork: Flow<WifiNetworkModel> = conflatedCallbackFlow {
+ var currentWifi: WifiNetworkModel = WIFI_NETWORK_DEFAULT
+
+ val callback = object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
+ override fun onCapabilitiesChanged(
+ network: Network,
+ networkCapabilities: NetworkCapabilities
+ ) {
+ logger.logOnCapabilitiesChanged(network, networkCapabilities)
+
+ val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
+ if (wifiInfo?.isPrimary == true) {
+ val wifiNetworkModel = wifiInfoToModel(wifiInfo, network.getNetId())
+ logger.logTransformation(
+ WIFI_NETWORK_CALLBACK_NAME,
+ oldValue = currentWifi,
+ newValue = wifiNetworkModel
+ )
+ currentWifi = wifiNetworkModel
+ trySend(wifiNetworkModel)
+ }
+ }
+
+ override fun onLost(network: Network) {
+ logger.logOnLost(network)
+ val wifi = currentWifi
+ if (wifi is WifiNetworkModel.Active && wifi.networkId == network.getNetId()) {
+ val newNetworkModel = WifiNetworkModel.Inactive
+ logger.logTransformation(
+ WIFI_NETWORK_CALLBACK_NAME,
+ oldValue = wifi,
+ newValue = newNetworkModel
+ )
+ currentWifi = newNetworkModel
+ trySend(newNetworkModel)
+ }
+ }
+ }
+
+ trySend(WIFI_NETWORK_DEFAULT)
+ connectivityManager.registerNetworkCallback(WIFI_NETWORK_CALLBACK_REQUEST, callback)
+
+ awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
+ }
+
+ override val wifiActivity: Flow<WifiActivityModel> =
+ if (wifiManager == null) {
+ Log.w(SB_LOGGING_TAG, "Null WifiManager; skipping activity callback")
+ flowOf(ACTIVITY_DEFAULT)
+ } else {
+ conflatedCallbackFlow {
+ val callback = TrafficStateCallback { state ->
+ logger.logInputChange("onTrafficStateChange", prettyPrintActivity(state))
+ trySend(trafficStateToWifiActivityModel(state))
+ }
+
+ trySend(ACTIVITY_DEFAULT)
+ wifiManager.registerTrafficStateCallback(mainExecutor, callback)
+
+ awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
+ }
+ }
+
+ companion object {
+ val ACTIVITY_DEFAULT = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
+ // Start out with no known wifi network.
+ // Note: [WifiStatusTracker] (the old implementation of connectivity logic) does do an
+ // initial fetch to get a starting wifi network. But, it uses a deprecated API
+ // [WifiManager.getConnectionInfo()], and the deprecation doc indicates to just use
+ // [ConnectivityManager.NetworkCallback] results instead. So, for now we'll just rely on the
+ // NetworkCallback inside [wifiNetwork] for our wifi network information.
+ val WIFI_NETWORK_DEFAULT = WifiNetworkModel.Inactive
+
+ private fun trafficStateToWifiActivityModel(state: Int): WifiActivityModel {
+ return WifiActivityModel(
+ hasActivityIn = state == TrafficStateCallback.DATA_ACTIVITY_IN ||
+ state == TrafficStateCallback.DATA_ACTIVITY_INOUT,
+ hasActivityOut = state == TrafficStateCallback.DATA_ACTIVITY_OUT ||
+ state == TrafficStateCallback.DATA_ACTIVITY_INOUT,
+ )
+ }
+
+ private fun networkCapabilitiesToWifiInfo(
+ networkCapabilities: NetworkCapabilities
+ ): WifiInfo? {
+ return when {
+ networkCapabilities.hasTransport(TRANSPORT_WIFI) ->
+ networkCapabilities.transportInfo as WifiInfo?
+ networkCapabilities.hasTransport(TRANSPORT_CELLULAR) ->
+ // Sometimes, cellular networks can act as wifi networks (known as VCN --
+ // virtual carrier network). So, see if this cellular network has wifi info.
+ Utils.tryGetWifiInfoForVcn(networkCapabilities)
+ else -> null
+ }
+ }
+
+ private fun wifiInfoToModel(wifiInfo: WifiInfo, networkId: Int): WifiNetworkModel {
+ return WifiNetworkModel.Active(
+ networkId,
+ wifiInfo.ssid,
+ wifiInfo.isPasspointAp,
+ wifiInfo.isOsuAp,
+ wifiInfo.passpointProviderFriendlyName
+ )
+ }
+
+ private fun prettyPrintActivity(activity: Int): String {
+ return when (activity) {
+ TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
+ TrafficStateCallback.DATA_ACTIVITY_IN -> "IN"
+ TrafficStateCallback.DATA_ACTIVITY_OUT -> "OUT"
+ TrafficStateCallback.DATA_ACTIVITY_INOUT -> "INOUT"
+ else -> "INVALID"
+ }
+ }
+
+ private val WIFI_NETWORK_CALLBACK_REQUEST: NetworkRequest =
+ NetworkRequest.Builder()
+ .clearCapabilities()
+ .addCapability(NET_CAPABILITY_NOT_VPN)
+ .addTransportType(TRANSPORT_WIFI)
+ .addTransportType(TRANSPORT_CELLULAR)
+ .build()
+
+ private const val WIFI_NETWORK_CALLBACK_NAME = "wifiNetworkModel"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
new file mode 100644
index 0000000..a9da63b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.domain.interactor
+
+import android.net.wifi.WifiManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+
+/**
+ * The business logic layer for the wifi icon.
+ *
+ * This interactor processes information from our data layer into information that the UI layer can
+ * use.
+ */
+@SysUISingleton
+class WifiInteractor @Inject constructor(
+ repository: WifiRepository,
+) {
+ private val ssid: Flow<String?> = repository.wifiNetwork.map { info ->
+ when (info) {
+ is WifiNetworkModel.Inactive -> null
+ is WifiNetworkModel.Active -> when {
+ info.isPasspointAccessPoint || info.isOnlineSignUpForPasspointAccessPoint ->
+ info.passpointProviderFriendlyName
+ info.ssid != WifiManager.UNKNOWN_SSID -> info.ssid
+ else -> null
+ }
+ }
+ }
+
+ val hasActivityIn: Flow<Boolean> = combine(repository.wifiActivity, ssid) { activity, ssid ->
+ activity.hasActivityIn && ssid != null
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
new file mode 100644
index 0000000..a19d1bd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.shared
+
+import android.content.Context
+import com.android.systemui.Dumpable
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * An object storing constants that we use for calculating the wifi icon. Stored in a class for
+ * logging purposes.
+ */
+@SysUISingleton
+class WifiConstants @Inject constructor(
+ context: Context,
+ dumpManager: DumpManager,
+) : Dumpable {
+ init {
+ dumpManager.registerDumpable("$SB_LOGGING_TAG:WifiConstants", this)
+ }
+
+ /** True if we should show the activityIn/activityOut icons and false otherwise. */
+ val shouldShowActivityConfig = context.resources.getBoolean(R.bool.config_showActivity)
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.apply {
+ println("shouldShowActivityConfig=$shouldShowActivityConfig")
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
new file mode 100644
index 0000000..b990eb7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
+
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
+import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+
+/**
+ * Models the UI state for the status bar wifi icon.
+ *
+ * TODO(b/238425913): Hook this up to the real status bar wifi view using a view binder.
+ */
+class WifiViewModel @Inject constructor(
+ private val constants: WifiConstants,
+ private val logger: ConnectivityPipelineLogger,
+ private val interactor: WifiInteractor,
+) {
+ val isActivityInVisible: Flow<Boolean>
+ get() =
+ if (!constants.shouldShowActivityConfig) {
+ flowOf(false)
+ } else {
+ interactor.hasActivityIn
+ }
+ .logOutputChange(logger, "activityInVisible")
+}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 094490b..adef182 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -244,7 +244,8 @@
final int currentUser = mUserTracker.getUserId();
final boolean hadWallpaperColors = mCurrentColors.get(userId) != null;
int latestWallpaperType = getLatestWallpaperType(userId);
- if ((flags & latestWallpaperType) != 0) {
+ boolean eventForLatestWallpaper = (flags & latestWallpaperType) != 0;
+ if (eventForLatestWallpaper) {
mCurrentColors.put(userId, wallpaperColors);
if (DEBUG) Log.d(TAG, "got new colors: " + wallpaperColors + " where: " + flags);
}
@@ -280,14 +281,19 @@
currentUser);
boolean isDestinationBoth = (flags == (WallpaperManager.FLAG_SYSTEM
| WallpaperManager.FLAG_LOCK));
+ boolean isDestinationHomeOnly = (flags == WallpaperManager.FLAG_SYSTEM);
try {
JSONObject jsonObject = (overlayPackageJson == null) ? new JSONObject()
: new JSONObject(overlayPackageJson);
// The latest applied wallpaper should be the source of system colors when:
// There is not preset color applied and the incoming wallpaper color is not applied
- if (!COLOR_SOURCE_PRESET.equals(jsonObject.optString(OVERLAY_COLOR_SOURCE))
- && ((flags & latestWallpaperType) != 0 && !isSeedColorSet(jsonObject,
- wallpaperColors))) {
+ String wallpaperPickerColorSource = jsonObject.optString(OVERLAY_COLOR_SOURCE);
+ boolean userChosePresetColor = COLOR_SOURCE_PRESET.equals(wallpaperPickerColorSource);
+ boolean userChoseLockScreenColor = COLOR_SOURCE_LOCK.equals(wallpaperPickerColorSource);
+ boolean preserveLockScreenColor = isDestinationHomeOnly && userChoseLockScreenColor;
+
+ if (!userChosePresetColor && !preserveLockScreenColor && eventForLatestWallpaper
+ && !isSeedColorSet(jsonObject, wallpaperColors)) {
mSkipSettingChange = true;
if (jsonObject.has(OVERLAY_CATEGORY_ACCENT_COLOR) || jsonObject.has(
OVERLAY_CATEGORY_SYSTEM_PALETTE)) {
@@ -642,7 +648,7 @@
}
if (mNeedsOverlayCreation) {
mNeedsOverlayCreation = false;
- mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] {
+ mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[]{
mSecondaryOverlay, mNeutralOverlay
}, currentUser, managedProfiles);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index 8f2a432..fc20ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -138,7 +138,7 @@
ensureOverlayRemoved()
- val newRoot = SurfaceControlViewHost(context, context.display!!, wwm, false)
+ val newRoot = SurfaceControlViewHost(context, context.display!!, wwm)
val newView =
LightRevealScrim(context, null).apply {
revealEffect = createLightRevealEffect()
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 345fc99..4dc78f9 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -21,6 +21,7 @@
import android.app.Notification.Action;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -215,9 +216,11 @@
} else {
// Boo, annoy the user to reinsert the private volume
- final CharSequence title = mContext.getString(R.string.ext_media_missing_title,
+ final CharSequence title =
+ mContext.getString(R.string.ext_media_missing_title,
rec.getNickname());
- final CharSequence text = mContext.getString(R.string.ext_media_missing_message);
+ final CharSequence text =
+ mContext.getString(R.string.ext_media_missing_message);
Notification.Builder builder =
new Notification.Builder(mContext, NotificationChannels.STORAGE)
@@ -381,8 +384,8 @@
if (rec.isSnoozed() && disk.isAdoptable()) {
return null;
}
-
- if (disk.isAdoptable() && !rec.isInited()) {
+ if (disk.isAdoptable() && !rec.isInited() && rec.getType() != VolumeInfo.TYPE_PUBLIC
+ && rec.getType() != VolumeInfo.TYPE_PRIVATE) {
final CharSequence title = disk.getDescription();
final CharSequence text = mContext.getString(
R.string.ext_media_new_notification_message, disk.getDescription());
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 4c76270..aeab2df 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -38,6 +38,7 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.dreams.IDreamManager;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.ZenModeConfig;
import android.util.Log;
@@ -101,6 +102,7 @@
private final ShadeController mShadeController;
private final IStatusBarService mBarService;
private final INotificationManager mNotificationManager;
+ private final IDreamManager mDreamManager;
private final NotificationVisibilityProvider mVisibilityProvider;
private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final NotificationLockscreenUserManager mNotifUserManager;
@@ -126,6 +128,7 @@
ShadeController shadeController,
@Nullable IStatusBarService statusBarService,
INotificationManager notificationManager,
+ IDreamManager dreamManager,
NotificationVisibilityProvider visibilityProvider,
NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
@@ -144,6 +147,7 @@
shadeController,
statusBarService,
notificationManager,
+ dreamManager,
visibilityProvider,
interruptionStateProvider,
zenModeController,
@@ -167,6 +171,7 @@
ShadeController shadeController,
@Nullable IStatusBarService statusBarService,
INotificationManager notificationManager,
+ IDreamManager dreamManager,
NotificationVisibilityProvider visibilityProvider,
NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
@@ -182,6 +187,7 @@
mNotificationShadeWindowController = notificationShadeWindowController;
mShadeController = shadeController;
mNotificationManager = notificationManager;
+ mDreamManager = dreamManager;
mVisibilityProvider = visibilityProvider;
mNotificationInterruptStateProvider = interruptionStateProvider;
mNotifUserManager = notifUserManager;
@@ -203,7 +209,7 @@
@Override
public void onKeyguardShowingChanged() {
boolean isUnlockedShade = !keyguardStateController.isShowing()
- && !keyguardStateController.isOccluded();
+ && !isDreamingOrInPreview();
bubbles.onStatusBarStateChanged(isUnlockedShade);
}
});
@@ -397,6 +403,15 @@
mBubbles.setSysuiProxy(mSysuiProxy);
}
+ private boolean isDreamingOrInPreview() {
+ try {
+ return mDreamManager.isDreamingOrInPreview();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to query dream manager.", e);
+ return false;
+ }
+ }
+
private void setupNotifPipeline() {
mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
@Override
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 763a5cb..ba28045 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -53,7 +53,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS" />
- <application android:debuggable="true" android:largeHeap="true">
+ <application android:debuggable="true" android:largeHeap="true"
+ android:enableOnBackInvokedCallback="true" >
<uses-library android:name="android.test.runner" />
<receiver android:name="com.android.systemui.SliceBroadcastRelayHandlerTest$Receiver"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index 01309f8..7f6b79b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -308,6 +308,12 @@
}
@Test
+ public void testOnViewDetachedRemovesViews() {
+ mController.onViewDetached();
+ verify(mView).removeAllStatusBarItemViews();
+ }
+
+ @Test
public void testWifiIconHiddenWhenWifiBecomesAvailable() {
// Make sure wifi starts out unavailable when onViewAttached is called, and then returns
// true on the second query.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index 141a213..b42b769 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -42,8 +42,11 @@
import android.testing.TestableLooper;
import android.view.GestureDetector;
import android.view.IWindowManager;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManagerPolicyConstants;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
import androidx.test.filters.SmallTest;
@@ -73,6 +76,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -117,6 +122,8 @@
@Mock private CentralSurfaces mCentralSurfaces;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private DialogLaunchAnimator mDialogLaunchAnimator;
+ @Mock private OnBackInvokedDispatcher mOnBackInvokedDispatcher;
+ @Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
private TestableLooper mTestableLooper;
@@ -203,6 +210,58 @@
}
@Test
+ public void testPredictiveBackCallbackRegisteredAndUnregistered() {
+ mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
+ doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+ doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
+ doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
+ String[] actions = {
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
+ };
+ doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
+
+ GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
+ dialog.setBackDispatcherOverride(mOnBackInvokedDispatcher);
+ dialog.create();
+ mTestableLooper.processAllMessages();
+ verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+ eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any());
+ dialog.onDetachedFromWindow();
+ mTestableLooper.processAllMessages();
+ verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(any());
+ }
+
+ @Test
+ public void testPredictiveBackInvocationDismissesDialog() {
+ mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
+ doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+ doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
+ doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
+ String[] actions = {
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART,
+ };
+ doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
+
+ GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
+ dialog.create();
+ dialog.show();
+ mTestableLooper.processAllMessages();
+ dialog.getWindow().injectInputEvent(
+ new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
+ dialog.getWindow().injectInputEvent(
+ new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
+ mTestableLooper.processAllMessages();
+ verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_BACK);
+ assertThat(dialog.isShowing()).isFalse();
+ }
+
+ @Test
public void testSingleTap_logAndDismiss() {
mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 19491f4..14b85b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -37,6 +37,8 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
+import kotlin.math.max
+import kotlin.math.min
import kotlin.reflect.KClass
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -127,6 +129,7 @@
val testConfig =
TestConfig(
isVisible = true,
+ isClickable = true,
icon = mock(),
canShowWhileLocked = false,
intent = Intent("action"),
@@ -154,6 +157,7 @@
val config =
TestConfig(
isVisible = true,
+ isClickable = true,
icon = mock(),
canShowWhileLocked = false,
intent = null, // This will cause it to tell the system that the click was handled.
@@ -201,6 +205,7 @@
val testConfig =
TestConfig(
isVisible = true,
+ isClickable = true,
icon = mock(),
canShowWhileLocked = false,
intent = Intent("action"),
@@ -260,6 +265,7 @@
testConfig =
TestConfig(
isVisible = true,
+ isClickable = true,
icon = mock(),
canShowWhileLocked = true,
)
@@ -269,6 +275,7 @@
testConfig =
TestConfig(
isVisible = true,
+ isClickable = true,
icon = mock(),
canShowWhileLocked = false,
)
@@ -342,6 +349,129 @@
job.cancel()
}
+ @Test
+ fun `isClickable - true when alpha at threshold`() = runBlockingTest {
+ repository.setKeyguardShowing(true)
+ repository.setBottomAreaAlpha(
+ KeyguardBottomAreaViewModel.AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD
+ )
+
+ val testConfig =
+ TestConfig(
+ isVisible = true,
+ isClickable = true,
+ icon = mock(),
+ canShowWhileLocked = false,
+ intent = Intent("action"),
+ )
+ val configKey =
+ setUpQuickAffordanceModel(
+ position = KeyguardQuickAffordancePosition.BOTTOM_START,
+ testConfig = testConfig,
+ )
+
+ var latest: KeyguardQuickAffordanceViewModel? = null
+ val job = underTest.startButton.onEach { latest = it }.launchIn(this)
+
+ assertQuickAffordanceViewModel(
+ viewModel = latest,
+ testConfig = testConfig,
+ configKey = configKey,
+ )
+ job.cancel()
+ }
+
+ @Test
+ fun `isClickable - true when alpha above threshold`() = runBlockingTest {
+ repository.setKeyguardShowing(true)
+ var latest: KeyguardQuickAffordanceViewModel? = null
+ val job = underTest.startButton.onEach { latest = it }.launchIn(this)
+ repository.setBottomAreaAlpha(
+ min(1f, KeyguardBottomAreaViewModel.AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD + 0.1f),
+ )
+
+ val testConfig =
+ TestConfig(
+ isVisible = true,
+ isClickable = true,
+ icon = mock(),
+ canShowWhileLocked = false,
+ intent = Intent("action"),
+ )
+ val configKey =
+ setUpQuickAffordanceModel(
+ position = KeyguardQuickAffordancePosition.BOTTOM_START,
+ testConfig = testConfig,
+ )
+
+ assertQuickAffordanceViewModel(
+ viewModel = latest,
+ testConfig = testConfig,
+ configKey = configKey,
+ )
+ job.cancel()
+ }
+
+ @Test
+ fun `isClickable - false when alpha below threshold`() = runBlockingTest {
+ repository.setKeyguardShowing(true)
+ var latest: KeyguardQuickAffordanceViewModel? = null
+ val job = underTest.startButton.onEach { latest = it }.launchIn(this)
+ repository.setBottomAreaAlpha(
+ max(0f, KeyguardBottomAreaViewModel.AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD - 0.1f),
+ )
+
+ val testConfig =
+ TestConfig(
+ isVisible = true,
+ isClickable = false,
+ icon = mock(),
+ canShowWhileLocked = false,
+ intent = Intent("action"),
+ )
+ val configKey =
+ setUpQuickAffordanceModel(
+ position = KeyguardQuickAffordancePosition.BOTTOM_START,
+ testConfig = testConfig,
+ )
+
+ assertQuickAffordanceViewModel(
+ viewModel = latest,
+ testConfig = testConfig,
+ configKey = configKey,
+ )
+ job.cancel()
+ }
+
+ @Test
+ fun `isClickable - false when alpha at zero`() = runBlockingTest {
+ repository.setKeyguardShowing(true)
+ var latest: KeyguardQuickAffordanceViewModel? = null
+ val job = underTest.startButton.onEach { latest = it }.launchIn(this)
+ repository.setBottomAreaAlpha(0f)
+
+ val testConfig =
+ TestConfig(
+ isVisible = true,
+ isClickable = false,
+ icon = mock(),
+ canShowWhileLocked = false,
+ intent = Intent("action"),
+ )
+ val configKey =
+ setUpQuickAffordanceModel(
+ position = KeyguardQuickAffordancePosition.BOTTOM_START,
+ testConfig = testConfig,
+ )
+
+ assertQuickAffordanceViewModel(
+ viewModel = latest,
+ testConfig = testConfig,
+ configKey = configKey,
+ )
+ job.cancel()
+ }
+
private suspend fun setDozeAmountAndCalculateExpectedTranslationY(dozeAmount: Float): Float {
repository.setDozeAmount(dozeAmount)
return dozeAmount * (RETURNED_BURN_IN_OFFSET - DEFAULT_BURN_IN_OFFSET)
@@ -384,6 +514,7 @@
) {
checkNotNull(viewModel)
assertThat(viewModel.isVisible).isEqualTo(testConfig.isVisible)
+ assertThat(viewModel.isClickable).isEqualTo(testConfig.isClickable)
if (testConfig.isVisible) {
assertThat(viewModel.icon).isEqualTo(testConfig.icon)
viewModel.onClicked.invoke(
@@ -404,6 +535,7 @@
private data class TestConfig(
val isVisible: Boolean,
+ val isClickable: Boolean = false,
val icon: ContainedDrawable? = null,
val canShowWhileLocked: Boolean = false,
val intent: Intent? = null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/InstantTaskExecutorRule.kt b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/InstantTaskExecutorRule.kt
new file mode 100644
index 0000000..373af5c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/InstantTaskExecutorRule.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.lifecycle
+
+import androidx.arch.core.executor.ArchTaskExecutor
+import androidx.arch.core.executor.TaskExecutor
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+
+/**
+ * Test rule that makes ArchTaskExecutor main thread assertions pass. There is one such assert
+ * in LifecycleRegistry.
+ */
+class InstantTaskExecutorRule : TestWatcher() {
+ // TODO(b/240620122): This is a copy of
+ // androidx/arch/core/executor/testing/InstantTaskExecutorRule which should be replaced
+ // with a dependency on the real library once b/ is cleared.
+ override fun starting(description: Description) {
+ super.starting(description)
+ ArchTaskExecutor.getInstance()
+ .setDelegate(
+ object : TaskExecutor() {
+ override fun executeOnDiskIO(runnable: Runnable) {
+ runnable.run()
+ }
+
+ override fun postToMainThread(runnable: Runnable) {
+ runnable.run()
+ }
+
+ override fun isMainThread(): Boolean {
+ return true
+ }
+ }
+ )
+ }
+
+ override fun finished(description: Description) {
+ super.finished(description)
+ ArchTaskExecutor.getInstance().setDelegate(null)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt
index 80f3e46..91a6de6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/lifecycle/RepeatWhenAttachedTest.kt
@@ -20,8 +20,6 @@
import android.testing.TestableLooper.RunWithLooper
import android.view.View
import android.view.ViewTreeObserver
-import androidx.arch.core.executor.ArchTaskExecutor
-import androidx.arch.core.executor.TaskExecutor
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.test.filters.SmallTest
@@ -35,8 +33,6 @@
import org.junit.Before
import org.junit.Rule
import org.junit.Test
-import org.junit.rules.TestWatcher
-import org.junit.runner.Description
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mock
@@ -282,38 +278,4 @@
_invocations.add(Invocation(lifecycleOwner))
}
}
-
- /**
- * Test rule that makes ArchTaskExecutor main thread assertions pass. There is one such assert
- * in LifecycleRegistry.
- */
- class InstantTaskExecutorRule : TestWatcher() {
- // TODO(b/240620122): This is a copy of
- // androidx/arch/core/executor/testing/InstantTaskExecutorRule which should be replaced
- // with a dependency on the real library once b/ is cleared.
- override fun starting(description: Description) {
- super.starting(description)
- ArchTaskExecutor.getInstance()
- .setDelegate(
- object : TaskExecutor() {
- override fun executeOnDiskIO(runnable: Runnable) {
- runnable.run()
- }
-
- override fun postToMainThread(runnable: Runnable) {
- runnable.run()
- }
-
- override fun isMainThread(): Boolean {
- return true
- }
- }
- )
- }
-
- override fun finished(description: Description) {
- super.finished(description)
- ArchTaskExecutor.getInstance().setDelegate(null)
- }
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index fcfef4a4..c41fac7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -16,19 +16,22 @@
package com.android.systemui.media
+import android.provider.Settings
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.FrameLayout
import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.MediaContainerView
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.animation.UniqueObjectHostView
+import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.utils.os.FakeHandler
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertTrue
import org.junit.Before
@@ -37,11 +40,12 @@
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
@SmallTest
@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
class KeyguardMediaControllerTest : SysuiTestCase() {
@Mock
@@ -53,31 +57,33 @@
@Mock
private lateinit var configurationController: ConfigurationController
- @Mock
- private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
@JvmField @Rule
val mockito = MockitoJUnit.rule()
private val mediaContainerView: MediaContainerView = MediaContainerView(context, null)
private val hostView = UniqueObjectHostView(context)
+ private val settings = FakeSettings()
private lateinit var keyguardMediaController: KeyguardMediaController
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var fakeHandler: FakeHandler
@Before
fun setup() {
// default state is positive, media should show up
whenever(mediaHost.visible).thenReturn(true)
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
- whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
- .thenReturn(true)
whenever(mediaHost.hostView).thenReturn(hostView)
hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
+ testableLooper = TestableLooper.get(this)
+ fakeHandler = FakeHandler(testableLooper.looper)
keyguardMediaController = KeyguardMediaController(
mediaHost,
bypassController,
statusBarStateController,
- notificationLockscreenUserManager,
context,
- configurationController
+ settings,
+ fakeHandler,
+ configurationController,
)
keyguardMediaController.attachSinglePaneContainer(mediaContainerView)
keyguardMediaController.useSplitShade = false
@@ -106,9 +112,8 @@
}
@Test
- fun testHiddenOnKeyguard_whenNotificationsAreHidden() {
- whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
- .thenReturn(false)
+ fun testHiddenOnKeyguard_whenMediaOnLockScreenDisabled() {
+ settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 0)
keyguardMediaController.refreshMediaPosition()
@@ -116,6 +121,15 @@
}
@Test
+ fun testAvailableOnKeyguard_whenMediaOnLockScreenEnabled() {
+ settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1)
+
+ keyguardMediaController.refreshMediaPosition()
+
+ assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE)
+ }
+
+ @Test
fun testActivatesSplitShadeContainerInSplitShadeMode() {
val splitShadeContainer = FrameLayout(context)
keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 1cce7cf..d1ed8e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -50,11 +50,10 @@
import org.mockito.Mockito
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
-import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
private const val KEY = "KEY"
private const val KEY_2 = "KEY_2"
@@ -287,6 +286,30 @@
}
@Test
+ fun testOnNotificationAdded_hasSubstituteName_isUsed() {
+ val subName = "Substitute Name"
+ val notif = SbnBuilder().run {
+ modifyNotification(context).also {
+ it.extras = Bundle().apply {
+ putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName)
+ }
+ it.setStyle(MediaStyle().apply {
+ setMediaSession(session.sessionToken)
+ })
+ }
+ build()
+ }
+
+ mediaDataManager.onNotificationAdded(KEY, notif)
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
+ eq(0), eq(false))
+
+ assertThat(mediaDataCaptor.value!!.app).isEqualTo(subName)
+ }
+
+ @Test
fun testLoadMediaDataInBg_invalidTokenNoCrash() {
val bundle = Bundle()
// wrong data type
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index d65b6b3..18bfd04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -16,8 +16,8 @@
package com.android.systemui.media
-import org.mockito.Mockito.`when` as whenever
import android.graphics.Rect
+import android.provider.Settings
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.ViewGroup
@@ -30,7 +30,7 @@
import com.android.systemui.dreams.DreamOverlayStateController
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.shade.testing.FakeNotifPanelEvents
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.phone.KeyguardBypassController
@@ -38,6 +38,8 @@
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.utils.os.FakeHandler
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertNotNull
import org.junit.Before
@@ -50,10 +52,10 @@
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@SmallTest
@@ -61,32 +63,18 @@
@TestableLooper.RunWithLooper
class MediaHierarchyManagerTest : SysuiTestCase() {
- @Mock
- private lateinit var lockHost: MediaHost
- @Mock
- private lateinit var qsHost: MediaHost
- @Mock
- private lateinit var qqsHost: MediaHost
- @Mock
- private lateinit var bypassController: KeyguardBypassController
- @Mock
- private lateinit var keyguardStateController: KeyguardStateController
- @Mock
- private lateinit var statusBarStateController: SysuiStatusBarStateController
- @Mock
- private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
- @Mock
- private lateinit var mediaCarouselController: MediaCarouselController
- @Mock
- private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
- @Mock
- private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
- @Mock
- private lateinit var keyguardViewController: KeyguardViewController
- @Mock
- private lateinit var uniqueObjectHostView: UniqueObjectHostView
- @Mock
- private lateinit var dreamOverlayStateController: DreamOverlayStateController
+ @Mock private lateinit var lockHost: MediaHost
+ @Mock private lateinit var qsHost: MediaHost
+ @Mock private lateinit var qqsHost: MediaHost
+ @Mock private lateinit var bypassController: KeyguardBypassController
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+ @Mock private lateinit var mediaCarouselController: MediaCarouselController
+ @Mock private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
+ @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
+ @Mock private lateinit var keyguardViewController: KeyguardViewController
+ @Mock private lateinit var uniqueObjectHostView: UniqueObjectHostView
+ @Mock private lateinit var dreamOverlayStateController: DreamOverlayStateController
@Captor
private lateinit var wakefullnessObserver: ArgumentCaptor<(WakefulnessLifecycle.Observer)>
@Captor
@@ -94,34 +82,42 @@
@JvmField
@Rule
val mockito = MockitoJUnit.rule()
- private lateinit var mediaHiearchyManager: MediaHierarchyManager
+ private lateinit var mediaHierarchyManager: MediaHierarchyManager
private lateinit var mediaFrame: ViewGroup
private val configurationController = FakeConfigurationController()
+ private val notifPanelEvents = FakeNotifPanelEvents()
+ private val settings = FakeSettings()
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var fakeHandler: FakeHandler
@Before
fun setup() {
context.getOrCreateTestableResources().addOverride(
R.bool.config_use_split_notification_shade, false)
mediaFrame = FrameLayout(context)
- `when`(mediaCarouselController.mediaFrame).thenReturn(mediaFrame)
- mediaHiearchyManager = MediaHierarchyManager(
+ testableLooper = TestableLooper.get(this)
+ fakeHandler = FakeHandler(testableLooper.looper)
+ whenever(mediaCarouselController.mediaFrame).thenReturn(mediaFrame)
+ mediaHierarchyManager = MediaHierarchyManager(
context,
statusBarStateController,
keyguardStateController,
bypassController,
mediaCarouselController,
- notificationLockscreenUserManager,
+ keyguardViewController,
+ dreamOverlayStateController,
configurationController,
wakefulnessLifecycle,
- keyguardViewController,
- dreamOverlayStateController)
+ notifPanelEvents,
+ settings,
+ fakeHandler,)
verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
verify(statusBarStateController).addCallback(statusBarCallback.capture())
setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
setupHost(qsHost, MediaHierarchyManager.LOCATION_QS, QS_TOP)
setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
- `when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
- `when`(mediaCarouselController.mediaCarouselScrollHandler)
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
+ whenever(mediaCarouselController.mediaCarouselScrollHandler)
.thenReturn(mediaCarouselScrollHandler)
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
@@ -131,30 +127,30 @@
}
private fun setupHost(host: MediaHost, location: Int, top: Int) {
- `when`(host.location).thenReturn(location)
- `when`(host.currentBounds).thenReturn(Rect(0, top, 0, top))
- `when`(host.hostView).thenReturn(uniqueObjectHostView)
- `when`(host.visible).thenReturn(true)
- mediaHiearchyManager.register(host)
+ whenever(host.location).thenReturn(location)
+ whenever(host.currentBounds).thenReturn(Rect(0, top, 0, top))
+ whenever(host.hostView).thenReturn(uniqueObjectHostView)
+ whenever(host.visible).thenReturn(true)
+ mediaHierarchyManager.register(host)
}
@Test
fun testHostViewSetOnRegister() {
- val host = mediaHiearchyManager.register(lockHost)
+ val host = mediaHierarchyManager.register(lockHost)
verify(lockHost).hostView = eq(host)
}
@Test
fun testBlockedWhenScreenTurningOff() {
// Let's set it onto QS:
- mediaHiearchyManager.qsExpansion = 1.0f
+ mediaHierarchyManager.qsExpansion = 1.0f
verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
observer.onStartedGoingToSleep()
clearInvocations(mediaCarouselController)
- mediaHiearchyManager.qsExpansion = 0.0f
+ mediaHierarchyManager.qsExpansion = 0.0f
verify(mediaCarouselController, times(0))
.onDesiredLocationChanged(ArgumentMatchers.anyInt(),
any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
@@ -163,13 +159,13 @@
@Test
fun testAllowedWhenNotTurningOff() {
// Let's set it onto QS:
- mediaHiearchyManager.qsExpansion = 1.0f
+ mediaHierarchyManager.qsExpansion = 1.0f
verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
clearInvocations(mediaCarouselController)
- mediaHiearchyManager.qsExpansion = 0.0f
+ mediaHierarchyManager.qsExpansion = 0.0f
verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
}
@@ -179,7 +175,7 @@
goToLockscreen()
// Let's transition all the way to full shade
- mediaHiearchyManager.setTransitionToFullShadeAmount(100000f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(100000f)
verify(mediaCarouselController).onDesiredLocationChanged(
eq(MediaHierarchyManager.LOCATION_QQS),
any(MediaHostState::class.java),
@@ -189,7 +185,7 @@
clearInvocations(mediaCarouselController)
// Let's go back to the lock screen
- mediaHiearchyManager.setTransitionToFullShadeAmount(0.0f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(0.0f)
verify(mediaCarouselController).onDesiredLocationChanged(
eq(MediaHierarchyManager.LOCATION_LOCKSCREEN),
any(MediaHostState::class.java),
@@ -198,7 +194,7 @@
anyLong())
// Let's make sure alpha is set
- mediaHiearchyManager.setTransitionToFullShadeAmount(2.0f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(2.0f)
assertThat(mediaFrame.alpha).isNotEqualTo(1.0f)
}
@@ -207,7 +203,26 @@
goToLockscreen()
expandQS()
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
+ assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ }
+
+ @Test
+ fun calculateTransformationType_notOnLockscreen_returnsTransition() {
+ expandQS()
+
+ val transformType = mediaHierarchyManager.calculateTransformationType()
+
+ assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION)
+ }
+
+ @Test
+ fun calculateTransformationType_onLockscreen_returnsTransition() {
+ goToLockscreen()
+ expandQS()
+
+ val transformType = mediaHierarchyManager.calculateTransformationType()
+
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
}
@@ -216,9 +231,9 @@
enableSplitShade()
goToLockscreen()
expandQS()
- mediaHiearchyManager.setTransitionToFullShadeAmount(10000f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(10000f)
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION)
}
@@ -228,9 +243,9 @@
goToLockscreen()
expandQS()
whenever(lockHost.visible).thenReturn(false)
- mediaHiearchyManager.setTransitionToFullShadeAmount(10000f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(10000f)
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
}
@@ -240,9 +255,9 @@
goToLockscreen()
goToLockedShade()
expandQS()
- mediaHiearchyManager.setTransitionToFullShadeAmount(0f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(0f)
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
}
@@ -251,13 +266,13 @@
goToLockscreen()
goToLockedShade()
- val transformType = mediaHiearchyManager.calculateTransformationType()
+ val transformType = mediaHierarchyManager.calculateTransformationType()
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
}
@Test
fun testCloseGutsRelayToCarousel() {
- mediaHiearchyManager.closeGuts()
+ mediaHierarchyManager.closeGuts()
verify(mediaCarouselController).closeGuts()
}
@@ -271,7 +286,7 @@
@Test
fun getGuidedTransformationTranslationY_notInGuidedTransformation_returnsNegativeNumber() {
- assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY()).isLessThan(0)
+ assertThat(mediaHierarchyManager.getGuidedTransformationTranslationY()).isLessThan(0)
}
@Test
@@ -279,7 +294,7 @@
enterGuidedTransformation()
val expectedTranslation = LOCKSCREEN_TOP - QS_TOP
- assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY())
+ assertThat(mediaHierarchyManager.getGuidedTransformationTranslationY())
.isEqualTo(expectedTranslation)
}
@@ -291,7 +306,19 @@
whenever(qsHost.visible).thenReturn(true)
whenever(qqsHost.visible).thenReturn(true)
- assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isTrue()
+ assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isTrue()
+ }
+
+ @Test
+ fun isCurrentlyInGuidedTransformation_hostsVisible_expandImmediateEnabled_returnsFalse() {
+ notifPanelEvents.changeExpandImmediate(expandImmediate = true)
+ goToLockscreen()
+ enterGuidedTransformation()
+ whenever(lockHost.visible).thenReturn(true)
+ whenever(qsHost.visible).thenReturn(true)
+ whenever(qqsHost.visible).thenReturn(true)
+
+ assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse()
}
@Test
@@ -302,7 +329,7 @@
whenever(qsHost.visible).thenReturn(true)
whenever(qqsHost.visible).thenReturn(true)
- assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isFalse()
+ assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse()
}
private fun enableSplitShade() {
@@ -314,9 +341,7 @@
private fun goToLockscreen() {
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
- whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
- true
- )
+ settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1)
statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
clearInvocations(mediaCarouselController)
}
@@ -330,13 +355,13 @@
}
private fun expandQS() {
- mediaHiearchyManager.qsExpansion = 1.0f
+ mediaHierarchyManager.qsExpansion = 1.0f
}
private fun enterGuidedTransformation() {
- mediaHiearchyManager.qsExpansion = 1.0f
+ mediaHierarchyManager.qsExpansion = 1.0f
goToLockscreen()
- mediaHiearchyManager.setTransitionToFullShadeAmount(123f)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(123f)
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 2aab9e8..1131a7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -24,9 +24,9 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.KeyguardManager;
import android.content.Context;
import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
@@ -88,6 +88,7 @@
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private final AudioManager mAudioManager = mock(AudioManager.class);
private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class);
+ private KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
private List<MediaController> mMediaControllers = new ArrayList<>();
private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
@@ -119,7 +120,8 @@
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
- Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager);
+ Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
+ mKeyguardManager);
mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext, mBroadcastSender,
mMediaOutputController);
mMediaOutputBaseDialogImpl.onCreate(new Bundle());
@@ -293,7 +295,7 @@
}
@Override
- Drawable getAppSourceIcon() {
+ IconCompat getAppSourceIcon() {
return null;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index 751c895..6dcf802 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -31,6 +31,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.content.Context;
import android.graphics.drawable.Icon;
@@ -47,6 +48,7 @@
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.text.TextUtils;
+import android.view.View;
import androidx.core.graphics.drawable.IconCompat;
import androidx.test.filters.SmallTest;
@@ -57,6 +59,7 @@
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
@@ -102,11 +105,16 @@
private RoutingSessionInfo mRemoteSessionInfo = mock(RoutingSessionInfo.class);
private ActivityStarter mStarter = mock(ActivityStarter.class);
private AudioManager mAudioManager = mock(AudioManager.class);
+ private KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class);
private CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
+ private final ActivityLaunchAnimator.Controller mActivityLaunchAnimatorController = mock(
+ ActivityLaunchAnimator.Controller.class);
private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
NearbyMediaDevicesManager.class);
+ private View mDialogLaunchView = mock(View.class);
+ private MediaOutputController.Callback mCallback = mock(MediaOutputController.Callback.class);
private Context mSpyContext;
private MediaOutputController mMediaOutputController;
@@ -131,7 +139,8 @@
mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME,
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
- Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager);
+ Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
+ mKeyguardManager);
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
@@ -183,7 +192,8 @@
mMediaOutputController = new MediaOutputController(mSpyContext, null,
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
- Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager);
+ Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
+ mKeyguardManager);
mMediaOutputController.start(mCb);
@@ -212,7 +222,8 @@
mMediaOutputController = new MediaOutputController(mSpyContext, null,
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
- Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager);
+ Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
+ mKeyguardManager);
mMediaOutputController.start(mCb);
@@ -461,7 +472,8 @@
mMediaOutputController = new MediaOutputController(mSpyContext, null,
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
- Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager);
+ Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
+ mKeyguardManager);
assertThat(mMediaOutputController.getNotificationIcon()).isNull();
}
@@ -557,4 +569,16 @@
verify(mPowerExemptionManager).addToTemporaryAllowList(anyString(), anyInt(), anyString(),
anyLong());
}
+
+ @Test
+ public void launchBluetoothPairing_isKeyguardLocked_dismissDialog() {
+ when(mDialogLaunchAnimator.createActivityLaunchController(mDialogLaunchView)).thenReturn(
+ mActivityLaunchAnimatorController);
+ when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
+ mMediaOutputController.mCallback = this.mCallback;
+
+ mMediaOutputController.launchBluetoothPairing(mDialogLaunchView);
+
+ verify(mCallback).dismissDialog();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index 4779d32..9557513 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -24,6 +24,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.KeyguardManager;
import android.media.AudioManager;
import android.media.MediaRoute2Info;
import android.media.session.MediaController;
@@ -85,6 +86,7 @@
NearbyMediaDevicesManager.class);
private final AudioManager mAudioManager = mock(AudioManager.class);
private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class);
+ private KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
private List<MediaController> mMediaControllers = new ArrayList<>();
private MediaOutputDialog mMediaOutputDialog;
@@ -104,7 +106,8 @@
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
mMediaSessionManager, mLocalBluetoothManager, mStarter,
mNotifCollection, mDialogLaunchAnimator,
- Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager);
+ Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
+ mKeyguardManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
mMediaOutputController, mUiEventLogger);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
index 247316a..c101b9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.media.dream;
+import static com.android.systemui.flags.Flags.MEDIA_DREAM_COMPLICATION;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
@@ -28,6 +30,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.MediaData;
import com.android.systemui.media.MediaDataManager;
@@ -50,6 +53,9 @@
@Mock
MediaDreamComplication mComplication;
+ @Mock
+ FeatureFlags mFeatureFlags;
+
final String mKey = "key";
final String mOldKey = "old_key";
@@ -59,21 +65,18 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+
+ when(mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)).thenReturn(true);
}
@Test
public void testComplicationAddition() {
final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
- mDreamOverlayStateController, mComplication);
+ mDreamOverlayStateController, mComplication, mFeatureFlags);
sentinel.start();
- ArgumentCaptor<MediaDataManager.Listener> listenerCaptor =
- ArgumentCaptor.forClass(MediaDataManager.Listener.class);
- verify(mMediaDataManager).addListener(listenerCaptor.capture());
-
- final MediaDataManager.Listener listener = listenerCaptor.getValue();
-
+ final MediaDataManager.Listener listener = captureMediaDataListener();
when(mMediaDataManager.hasActiveMedia()).thenReturn(false);
listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */ true,
/* receivedSmartspaceCardLatency= */ 0, /* isSsReactived= */ false);
@@ -92,4 +95,27 @@
verify(mDreamOverlayStateController).removeComplication(eq(mComplication));
}
+ @Test
+ public void testMediaDreamSentinel_mediaComplicationDisabled_doNotAddComplication() {
+ when(mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)).thenReturn(false);
+
+ final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
+ mDreamOverlayStateController, mComplication, mFeatureFlags);
+
+ sentinel.start();
+
+ final MediaDataManager.Listener listener = captureMediaDataListener();
+ when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
+ listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+ /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
+ verify(mDreamOverlayStateController, never()).addComplication(any());
+ }
+
+ private MediaDataManager.Listener captureMediaDataListener() {
+ final ArgumentCaptor<MediaDataManager.Listener> listenerCaptor =
+ ArgumentCaptor.forClass(MediaDataManager.Listener.class);
+ verify(mMediaDataManager).addListener(listenerCaptor.capture());
+
+ return listenerCaptor.getValue();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 1f28210..e4f47fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -17,8 +17,8 @@
package com.android.systemui.qs
import android.content.res.Configuration
-import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
@@ -38,38 +38,32 @@
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
+import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
class QuickQSPanelControllerTest : SysuiTestCase() {
- @Mock
- private lateinit var quickQSPanel: QuickQSPanel
- @Mock
- private lateinit var qsTileHost: QSTileHost
- @Mock
- private lateinit var qsCustomizerController: QSCustomizerController
- @Mock
- private lateinit var mediaHost: MediaHost
- @Mock
- private lateinit var metricsLogger: MetricsLogger
+ @Mock private lateinit var quickQSPanel: QuickQSPanel
+ @Mock private lateinit var qsTileHost: QSTileHost
+ @Mock private lateinit var qsCustomizerController: QSCustomizerController
+ @Mock private lateinit var mediaHost: MediaHost
+ @Mock private lateinit var metricsLogger: MetricsLogger
+ @Mock private lateinit var qsLogger: QSLogger
+ @Mock private lateinit var tile: QSTile
+ @Mock private lateinit var tileLayout: TileLayout
+ @Mock private lateinit var tileView: QSTileView
+ @Captor private lateinit var captor: ArgumentCaptor<QSPanel.OnConfigurationChangedListener>
+
private val uiEventLogger = UiEventLoggerFake()
- @Mock
- private lateinit var qsLogger: QSLogger
private val dumpManager = DumpManager()
- @Mock
- private lateinit var tile: QSTile
- @Mock
- private lateinit var tileLayout: TileLayout
- @Mock
- private lateinit var tileView: QSTileView
- @Captor
- private lateinit var captor: ArgumentCaptor<QSPanel.OnConfigurationChangedListener>
+
+ private var usingCollapsedLandscapeMedia = true
private lateinit var controller: TestQuickQSPanelController
@@ -77,24 +71,24 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- `when`(quickQSPanel.tileLayout).thenReturn(tileLayout)
- `when`(quickQSPanel.isAttachedToWindow).thenReturn(true)
- `when`(quickQSPanel.dumpableTag).thenReturn("")
- `when`(quickQSPanel.resources).thenReturn(mContext.resources)
- `when`(qsTileHost.createTileView(any(), any(), anyBoolean())).thenReturn(tileView)
+ whenever(quickQSPanel.tileLayout).thenReturn(tileLayout)
+ whenever(quickQSPanel.isAttachedToWindow).thenReturn(true)
+ whenever(quickQSPanel.dumpableTag).thenReturn("")
+ whenever(quickQSPanel.resources).thenReturn(mContext.resources)
+ whenever(qsTileHost.createTileView(any(), any(), anyBoolean())).thenReturn(tileView)
- controller = TestQuickQSPanelController(
+ controller =
+ TestQuickQSPanelController(
quickQSPanel,
qsTileHost,
qsCustomizerController,
- false,
+ /* usingMediaPlayer = */ false,
mediaHost,
- true,
+ { usingCollapsedLandscapeMedia },
metricsLogger,
uiEventLogger,
qsLogger,
- dumpManager
- )
+ dumpManager)
controller.init()
}
@@ -106,9 +100,9 @@
@Test
fun testTileSublistWithFewerTiles_noCrash() {
- `when`(quickQSPanel.numQuickTiles).thenReturn(3)
+ whenever(quickQSPanel.numQuickTiles).thenReturn(3)
- `when`(qsTileHost.tiles).thenReturn(listOf(tile, tile))
+ whenever(qsTileHost.tiles).thenReturn(listOf(tile, tile))
controller.setTiles()
}
@@ -116,8 +110,8 @@
@Test
fun testTileSublistWithTooManyTiles() {
val limit = 3
- `when`(quickQSPanel.numQuickTiles).thenReturn(limit)
- `when`(qsTileHost.tiles).thenReturn(listOf(tile, tile, tile, tile))
+ whenever(quickQSPanel.numQuickTiles).thenReturn(limit)
+ whenever(qsTileHost.tiles).thenReturn(listOf(tile, tile, tile, tile))
controller.setTiles()
@@ -125,39 +119,61 @@
}
@Test
- fun testMediaExpansionUpdatedWhenConfigurationChanged() {
+ fun mediaExpansion_afterConfigChange_inLandscape_collapsedInLandscapeTrue_updatesToCollapsed() {
// times(2) because both controller and base controller are registering their listeners
verify(quickQSPanel, times(2)).addOnConfigurationChangedListener(captor.capture())
// verify that media starts in the expanded state by default
verify(mediaHost).expansion = MediaHostState.EXPANDED
- // Rotate device, verify media size updated
+ // Rotate device, verify media size updated to collapsed
+ usingCollapsedLandscapeMedia = true
controller.setRotation(RotationUtils.ROTATION_LANDSCAPE)
captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) }
verify(mediaHost).expansion = MediaHostState.COLLAPSED
}
+ @Test
+ fun mediaExpansion_afterConfigChange_landscape_collapsedInLandscapeFalse_remainsExpanded() {
+ // times(2) because both controller and base controller are registering their listeners
+ verify(quickQSPanel, times(2)).addOnConfigurationChangedListener(captor.capture())
+ reset(mediaHost)
+
+ usingCollapsedLandscapeMedia = false
+ controller.setRotation(RotationUtils.ROTATION_LANDSCAPE)
+ captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) }
+
+ verify(mediaHost).expansion = MediaHostState.EXPANDED
+ }
+
class TestQuickQSPanelController(
view: QuickQSPanel,
qsTileHost: QSTileHost,
qsCustomizerController: QSCustomizerController,
usingMediaPlayer: Boolean,
mediaHost: MediaHost,
- usingCollapsedLandscapeMedia: Boolean,
+ usingCollapsedLandscapeMedia: () -> Boolean,
metricsLogger: MetricsLogger,
uiEventLogger: UiEventLoggerFake,
qsLogger: QSLogger,
dumpManager: DumpManager
- ) : QuickQSPanelController(view, qsTileHost, qsCustomizerController, usingMediaPlayer,
- mediaHost, usingCollapsedLandscapeMedia, metricsLogger, uiEventLogger, qsLogger,
- dumpManager) {
+ ) :
+ QuickQSPanelController(
+ view,
+ qsTileHost,
+ qsCustomizerController,
+ usingMediaPlayer,
+ mediaHost,
+ usingCollapsedLandscapeMedia,
+ metricsLogger,
+ uiEventLogger,
+ qsLogger,
+ dumpManager) {
private var rotation = RotationUtils.ROTATION_NONE
- @Override
- override fun getRotation(): Int = rotation
+ @Override override fun getRotation(): Int = rotation
fun setRotation(newRotation: Int) {
rotation = newRotation
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeImageCapture.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeImageCapture.kt
new file mode 100644
index 0000000..447e28c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeImageCapture.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.screenshot
+
+import android.graphics.Bitmap
+import android.graphics.Rect
+
+internal class FakeImageCapture : ImageCapture {
+
+ var requestedDisplayId: Int? = null
+ var requestedDisplayCrop: Rect? = null
+ var requestedTaskId: Int? = null
+
+ var image: Bitmap? = null
+
+ override fun captureDisplay(displayId: Int, crop: Rect?): Bitmap? {
+ requestedDisplayId = displayId
+ requestedDisplayCrop = crop
+ return image
+ }
+
+ override suspend fun captureTask(taskId: Int): Bitmap? {
+ requestedTaskId = taskId
+ return image
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
new file mode 100644
index 0000000..28d53c7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScreenshotPolicy.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
+
+internal class FakeScreenshotPolicy : ScreenshotPolicy {
+
+ private val userTypes = mutableMapOf<Int, Boolean>()
+ private val contentInfo = mutableMapOf<Int, DisplayContentInfo?>()
+
+ fun setManagedProfile(userId: Int, managedUser: Boolean) {
+ userTypes[userId] = managedUser
+ }
+ override suspend fun isManagedProfile(userId: Int): Boolean {
+ return userTypes[userId] ?: error("No managedProfile value set for userId $userId")
+ }
+
+ fun setDisplayContentInfo(userId: Int, contentInfo: DisplayContentInfo) {
+ this.contentInfo[userId] = contentInfo
+ }
+
+ override suspend fun findPrimaryContent(displayId: Int): DisplayContentInfo {
+ return contentInfo[displayId] ?: error("No DisplayContentInfo set for displayId $displayId")
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
index ce3f20d..00f3808 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
@@ -27,6 +27,8 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,7 +39,10 @@
class ImageCaptureImplTest : SysuiTestCase() {
private val displayManager = mock<DisplayManager>()
private val atmService = mock<IActivityTaskManager>()
- private val capture = TestableImageCaptureImpl(displayManager, atmService)
+ private val capture = TestableImageCaptureImpl(
+ displayManager,
+ atmService,
+ Dispatchers.Unconfined)
@Test
fun captureDisplayWithCrop() {
@@ -59,9 +64,10 @@
class TestableImageCaptureImpl(
displayManager: DisplayManager,
- atmService: IActivityTaskManager
+ atmService: IActivityTaskManager,
+ bgDispatcher: CoroutineDispatcher
) :
- ImageCaptureImpl(displayManager, atmService) {
+ ImageCaptureImpl(displayManager, atmService, bgDispatcher) {
var token: IBinder? = null
var width: Int? = null
@@ -81,4 +87,4 @@
return ScreenshotHardwareBuffer(null, null, false, false)
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
index 024d3bd..48fbd35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
@@ -22,86 +22,253 @@
import android.graphics.Insets
import android.graphics.Rect
import android.hardware.HardwareBuffer
-import android.net.Uri
+import android.os.Bundle
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER
import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
-import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
-
+import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
+import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap
import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
-import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback
-import com.android.systemui.util.mockito.argumentCaptor
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
import com.google.common.truth.Truth.assertThat
-import java.util.function.Consumer
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
import org.junit.Test
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.isNull
+
+private const val USER_ID = 1
+private const val TASK_ID = 1
class RequestProcessorTest {
- private val controller = mock<ScreenshotController>()
- private val bitmapCaptor = argumentCaptor<Bitmap>()
+ private val imageCapture = FakeImageCapture()
+ private val component = ComponentName("android.test", "android.test.Component")
+ private val bounds = Rect(25, 25, 75, 75)
+ private val scope = CoroutineScope(Dispatchers.Unconfined)
+ private val dispatcher = Dispatchers.Unconfined
+ private val policy = FakeScreenshotPolicy()
+ private val flags = FakeFeatureFlags()
+
+ /** Tests the Java-compatible function wrapper, ensures callback is invoked. */
@Test
- fun testFullScreenshot() {
+ fun testProcessAsync() {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
+
val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
- val onSavedListener = mock<Consumer<Uri>>()
- val callback = mock<RequestCallback>()
- val processor = RequestProcessor(controller)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
- processor.processRequest(request, onSavedListener, callback)
+ var result: ScreenshotRequest? = null
+ var callbackCount = 0
+ val callback: (ScreenshotRequest) -> Unit = { processedRequest: ScreenshotRequest ->
+ result = processedRequest
+ callbackCount++
+ }
- verify(controller).takeScreenshotFullscreen(/* topComponent */ isNull(),
- eq(onSavedListener), eq(callback))
+ // runs synchronously, using Unconfined Dispatcher
+ processor.processAsync(request, callback)
+
+ // Callback invoked once returning the same request (no changes)
+ assertThat(callbackCount).isEqualTo(1)
+ assertThat(result).isEqualTo(request)
}
@Test
- fun testSelectedRegionScreenshot() {
+ fun testFullScreenshot_workProfilePolicyDisabled() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ val processedRequest = processor.process(request)
+
+ // No changes
+ assertThat(processedRequest).isEqualTo(request)
+ }
+
+ @Test
+ fun testFullScreenshot() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
+
+ // Indicate that the primary content belongs to a normal user
+ policy.setManagedProfile(USER_ID, false)
+ policy.setDisplayContentInfo(
+ policy.getDefaultDisplayId(),
+ DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ val processedRequest = processor.process(request)
+
+ // Request has topComponent added, but otherwise unchanged.
+ assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_FULLSCREEN)
+ assertThat(processedRequest.topComponent).isEqualTo(component)
+ }
+
+ @Test
+ fun testFullScreenshot_managedProfile() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
+
+ // Provide a fake task bitmap when asked
+ val bitmap = makeHardwareBitmap(100, 100)
+ imageCapture.image = bitmap
+
+ // Indicate that the primary content belongs to a manged profile
+ policy.setManagedProfile(USER_ID, true)
+ policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
+ DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ val processedRequest = processor.process(request)
+
+ // Expect a task snapshot is taken, overriding the full screen mode
+ assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_PROVIDED_IMAGE)
+ assertThat(bitmap.equalsHardwareBitmapBundle(processedRequest.bitmapBundle)).isTrue()
+ assertThat(processedRequest.boundsInScreen).isEqualTo(bounds)
+ assertThat(processedRequest.insets).isEqualTo(Insets.NONE)
+ assertThat(processedRequest.taskId).isEqualTo(TASK_ID)
+ assertThat(imageCapture.requestedTaskId).isEqualTo(TASK_ID)
+ assertThat(processedRequest.userId).isEqualTo(USER_ID)
+ assertThat(processedRequest.topComponent).isEqualTo(component)
+ }
+
+ @Test
+ fun testSelectedRegionScreenshot_workProfilePolicyDisabled() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
+
val request = ScreenshotRequest(TAKE_SCREENSHOT_SELECTED_REGION, SCREENSHOT_KEY_CHORD)
- val onSavedListener = mock<Consumer<Uri>>()
- val callback = mock<RequestCallback>()
- val processor = RequestProcessor(controller)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
- processor.processRequest(request, onSavedListener, callback)
+ val processedRequest = processor.process(request)
- verify(controller).takeScreenshotPartial(/* topComponent */ isNull(),
- eq(onSavedListener), eq(callback))
+ // No changes
+ assertThat(processedRequest).isEqualTo(request)
+ }
+
+ @Test
+ fun testSelectedRegionScreenshot() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_SELECTED_REGION, SCREENSHOT_KEY_CHORD)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ policy.setManagedProfile(USER_ID, false)
+ policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
+ DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+
+ val processedRequest = processor.process(request)
+
+ // Request has topComponent added, but otherwise unchanged.
+ assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_FULLSCREEN)
+ assertThat(processedRequest.topComponent).isEqualTo(component)
}
@Test
- fun testProvidedImageScreenshot() {
- val taskId = 1111
- val userId = 2222
- val bounds = Rect(50, 50, 150, 150)
- val topComponent = ComponentName("test", "test")
- val processor = RequestProcessor(controller)
+ fun testSelectedRegionScreenshot_managedProfile() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
- val buffer = HardwareBuffer.create(100, 100, HardwareBuffer.RGBA_8888, 1,
- HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
- val bitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB))!!
+ // Provide a fake task bitmap when asked
+ val bitmap = makeHardwareBitmap(100, 100)
+ imageCapture.image = bitmap
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_SELECTED_REGION, SCREENSHOT_KEY_CHORD)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ // Indicate that the primary content belongs to a manged profile
+ policy.setManagedProfile(USER_ID, true)
+ policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
+ DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+
+ val processedRequest = processor.process(request)
+
+ // Expect a task snapshot is taken, overriding the selected region mode
+ assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_PROVIDED_IMAGE)
+ assertThat(bitmap.equalsHardwareBitmapBundle(processedRequest.bitmapBundle)).isTrue()
+ assertThat(processedRequest.boundsInScreen).isEqualTo(bounds)
+ assertThat(processedRequest.insets).isEqualTo(Insets.NONE)
+ assertThat(processedRequest.taskId).isEqualTo(TASK_ID)
+ assertThat(imageCapture.requestedTaskId).isEqualTo(TASK_ID)
+ assertThat(processedRequest.userId).isEqualTo(USER_ID)
+ assertThat(processedRequest.topComponent).isEqualTo(component)
+ }
+
+ @Test
+ fun testProvidedImageScreenshot_workProfilePolicyDisabled() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
+
+ val bounds = Rect(50, 50, 150, 150)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ val bitmap = makeHardwareBitmap(100, 100)
val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER,
- bitmapBundle, bounds, Insets.NONE, taskId, userId, topComponent)
+ bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component)
- val onSavedListener = mock<Consumer<Uri>>()
- val callback = mock<RequestCallback>()
+ val processedRequest = processor.process(request)
- processor.processRequest(request, onSavedListener, callback)
-
- verify(controller).handleImageAsScreenshot(
- bitmapCaptor.capture(), eq(bounds), eq(Insets.NONE), eq(taskId), eq(userId),
- eq(topComponent), eq(onSavedListener), eq(callback)
- )
-
- assertThat(bitmapCaptor.value.equalsHardwareBitmap(bitmap)).isTrue()
+ // No changes
+ assertThat(processedRequest).isEqualTo(request)
}
- private fun Bitmap.equalsHardwareBitmap(bitmap: Bitmap): Boolean {
- return bitmap.hardwareBuffer == this.hardwareBuffer &&
- bitmap.colorSpace == this.colorSpace
+ @Test
+ fun testProvidedImageScreenshot() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
+
+ val bounds = Rect(50, 50, 150, 150)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ policy.setManagedProfile(USER_ID, false)
+
+ val bitmap = makeHardwareBitmap(100, 100)
+ val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER,
+ bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component)
+
+ val processedRequest = processor.process(request)
+
+ // No changes
+ assertThat(processedRequest).isEqualTo(request)
+ }
+
+ @Test
+ fun testProvidedImageScreenshot_managedProfile() = runBlocking {
+ flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
+
+ val bounds = Rect(50, 50, 150, 150)
+ val processor = RequestProcessor(imageCapture, policy, flags, scope)
+
+ // Indicate that the screenshot belongs to a manged profile
+ policy.setManagedProfile(USER_ID, true)
+
+ val bitmap = makeHardwareBitmap(100, 100)
+ val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
+
+ val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER,
+ bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component)
+
+ val processedRequest = processor.process(request)
+
+ // Work profile, but already a task snapshot, so no changes
+ assertThat(processedRequest).isEqualTo(request)
+ }
+
+ private fun makeHardwareBitmap(width: Int, height: Int): Bitmap {
+ val buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888, 1,
+ HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
+ return Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB))!!
+ }
+
+ private fun Bitmap.equalsHardwareBitmapBundle(bundle: Bundle): Boolean {
+ val provided = bundleToHardwareBitmap(bundle)
+ return provided.hardwareBuffer == this.hardwareBuffer &&
+ provided.colorSpace == this.colorSpace
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 3f4e2a9..7d28871 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -47,7 +47,6 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
-import android.graphics.PointF;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
@@ -238,6 +237,8 @@
@Mock
private DozeLog mDozeLog;
@Mock
+ private ShadeLogger mShadeLog;
+ @Mock
private CommandQueue mCommandQueue;
@Mock
private VibratorHelper mVibratorHelper;
@@ -524,7 +525,9 @@
mNotificationShadeWindowController,
mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper,
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
- mMetricsLogger, mConfigurationController,
+ mMetricsLogger,
+ mShadeLog,
+ mConfigurationController,
() -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
mStatusBarKeyguardViewManager,
@@ -760,10 +763,8 @@
@Test
public void testSetDozing_notifiesNsslAndStateController() {
- mNotificationPanelViewController.setDozing(true /* dozing */, false /* animate */,
- null /* touch */);
- verify(mNotificationStackScrollLayoutController)
- .setDozing(eq(true), eq(false), eq(null));
+ mNotificationPanelViewController.setDozing(true /* dozing */, false /* animate */);
+ verify(mNotificationStackScrollLayoutController).setDozing(eq(true), eq(false));
assertThat(mStatusBarStateController.getDozeAmount()).isEqualTo(1f);
}
@@ -904,7 +905,7 @@
setDozing(/* dozing= */ true, /* dozingAlwaysOn= */ true);
- assertThat(isKeyguardStatusViewCentered()).isTrue();
+ assertKeyguardStatusViewCentered();
}
@Test
@@ -915,7 +916,7 @@
setDozing(/* dozing= */ true, /* dozingAlwaysOn= */ false);
- assertThat(isKeyguardStatusViewCentered()).isFalse();
+ assertKeyguardStatusViewNotCentered();
}
@Test
@@ -926,19 +927,19 @@
setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ true);
- assertThat(isKeyguardStatusViewCentered()).isFalse();
+ assertKeyguardStatusViewNotCentered();
}
@Test
- public void keyguardStatusView_splitShade_pulsing_isCentered() {
+ public void keyguardStatusView_splitShade_pulsing_isNotCentered() {
when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2);
when(mNotificationListContainer.hasPulsingNotifications()).thenReturn(true);
mStatusBarStateController.setState(KEYGUARD);
enableSplitShade(/* enabled= */ true);
- setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ true);
+ setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ false);
- assertThat(isKeyguardStatusViewCentered()).isFalse();
+ assertKeyguardStatusViewNotCentered();
}
@Test
@@ -948,9 +949,9 @@
mStatusBarStateController.setState(KEYGUARD);
enableSplitShade(/* enabled= */ true);
- setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ true);
+ setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ false);
- assertThat(isKeyguardStatusViewCentered()).isFalse();
+ assertKeyguardStatusViewNotCentered();
}
@Test
@@ -963,7 +964,7 @@
mStatusBarStateController.setState(KEYGUARD);
setDozing(/* dozing= */ false, /* dozingAlwaysOn= */ false);
- assertThat(isKeyguardStatusViewCentered()).isFalse();
+ assertKeyguardStatusViewCentered();
}
@Test
@@ -1208,16 +1209,31 @@
}
@Test
- public void testSwitchesToBigClockInSplitShadeOnAod() {
+ public void clockSize_mediaShowing_inSplitShade_onAod_isLarge() {
+ when(mDozeParameters.getAlwaysOn()).thenReturn(true);
mStatusBarStateController.setState(KEYGUARD);
enableSplitShade(/* enabled= */ true);
when(mMediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true);
when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2);
clearInvocations(mKeyguardStatusViewController);
- mNotificationPanelViewController.setDozing(true, false, null);
+ mNotificationPanelViewController.setDozing(/* dozing= */ true, /* animate= */ false);
- verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true);
+ verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate= */ true);
+ }
+
+ @Test
+ public void clockSize_mediaShowing_inSplitShade_screenOff_notAod_isSmall() {
+ when(mDozeParameters.getAlwaysOn()).thenReturn(false);
+ mStatusBarStateController.setState(KEYGUARD);
+ enableSplitShade(/* enabled= */ true);
+ when(mMediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true);
+ when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2);
+ clearInvocations(mKeyguardStatusViewController);
+
+ mNotificationPanelViewController.setDozing(/* dozing= */ true, /* animate= */ false);
+
+ verify(mKeyguardStatusViewController).displayClock(SMALL, /* animate= */ true);
}
@Test
@@ -1229,7 +1245,7 @@
when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2);
- mNotificationPanelViewController.setDozing(true, false, null);
+ mNotificationPanelViewController.setDozing(true, false);
verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ false);
}
@@ -1543,14 +1559,19 @@
when(mDozeParameters.getAlwaysOn()).thenReturn(dozingAlwaysOn);
mNotificationPanelViewController.setDozing(
/* dozing= */ dozing,
- /* animate= */ false,
- /* wakeUpTouchLocation= */ new PointF()
+ /* animate= */ false
);
}
- private boolean isKeyguardStatusViewCentered() {
+ private void assertKeyguardStatusViewCentered() {
mNotificationPanelViewController.updateResources();
- return getConstraintSetLayout(R.id.keyguard_status_view).endToEnd
- == ConstraintSet.PARENT_ID;
+ assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isAnyOf(
+ ConstraintSet.PARENT_ID, ConstraintSet.UNSET);
+ }
+
+ private void assertKeyguardStatusViewNotCentered() {
+ mNotificationPanelViewController.updateResources();
+ assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isEqualTo(
+ R.id.qs_edge_guideline);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/testing/FakeNotifPanelEvents.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/testing/FakeNotifPanelEvents.kt
new file mode 100644
index 0000000..d052138
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/testing/FakeNotifPanelEvents.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.testing
+
+import com.android.systemui.shade.NotifPanelEvents
+
+/** Fake implementation of [NotifPanelEvents] for testing. */
+class FakeNotifPanelEvents : NotifPanelEvents {
+
+ private val listeners = mutableListOf<NotifPanelEvents.Listener>()
+
+ override fun registerListener(listener: NotifPanelEvents.Listener) {
+ listeners.add(listener)
+ }
+
+ override fun unregisterListener(listener: NotifPanelEvents.Listener) {
+ listeners.remove(listener)
+ }
+
+ fun changeExpandImmediate(expandImmediate: Boolean) {
+ listeners.forEach { it.onExpandImmediateChanged(expandImmediate) }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplingInstanceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplingInstanceTest.kt
new file mode 100644
index 0000000..09d51f6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplingInstanceTest.kt
@@ -0,0 +1,113 @@
+package com.android.systemui.shared.regionsampling
+
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.shared.navigationbar.RegionSamplingHelper
+import java.io.PrintWriter
+import java.util.concurrent.Executor
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class RegionSamplingInstanceTest : SysuiTestCase() {
+
+ @JvmField @Rule
+ val mockito = MockitoJUnit.rule()
+
+ @Mock private lateinit var sampledView: View
+ @Mock private lateinit var mainExecutor: Executor
+ @Mock private lateinit var bgExecutor: Executor
+ @Mock private lateinit var regionSampler: RegionSamplingHelper
+ @Mock private lateinit var updateFun: RegionSamplingInstance.UpdateColorCallback
+ @Mock private lateinit var pw: PrintWriter
+ @Mock private lateinit var callback: RegionSamplingHelper.SamplingCallback
+
+ private lateinit var regionSamplingInstance: RegionSamplingInstance
+
+ @Before
+ fun setUp() {
+ whenever(sampledView.isAttachedToWindow).thenReturn(true)
+ whenever(regionSampler.callback).thenReturn(this@RegionSamplingInstanceTest.callback)
+
+ regionSamplingInstance = object : RegionSamplingInstance(
+ sampledView,
+ mainExecutor,
+ bgExecutor,
+ true,
+ updateFun
+ ) {
+ override fun createRegionSamplingHelper(
+ sampledView: View,
+ callback: RegionSamplingHelper.SamplingCallback,
+ mainExecutor: Executor?,
+ bgExecutor: Executor?
+ ): RegionSamplingHelper {
+ return this@RegionSamplingInstanceTest.regionSampler
+ }
+ }
+ }
+
+ @Test
+ fun testStartRegionSampler() {
+ regionSamplingInstance.startRegionSampler()
+
+ verify(regionSampler).start(Rect(0, 0, 0, 0))
+ }
+
+ @Test
+ fun testStopRegionSampler() {
+ regionSamplingInstance.stopRegionSampler()
+
+ verify(regionSampler).stop()
+ }
+
+ @Test
+ fun testDump() {
+ regionSamplingInstance.dump(pw)
+
+ verify(regionSampler).dump(pw)
+ }
+
+ @Test
+ fun testUpdateColorCallback() {
+ regionSampler.callback.onRegionDarknessChanged(false)
+ verify(regionSampler.callback).onRegionDarknessChanged(false)
+ clearInvocations(regionSampler.callback)
+ regionSampler.callback.onRegionDarknessChanged(true)
+ verify(regionSampler.callback).onRegionDarknessChanged(true)
+ }
+
+ @Test
+ fun testFlagFalse() {
+ regionSamplingInstance = object : RegionSamplingInstance(
+ sampledView,
+ mainExecutor,
+ bgExecutor,
+ false,
+ updateFun
+ ) {
+ override fun createRegionSamplingHelper(
+ sampledView: View,
+ callback: RegionSamplingHelper.SamplingCallback,
+ mainExecutor: Executor?,
+ bgExecutor: Executor?
+ ): RegionSamplingHelper {
+ return this@RegionSamplingInstanceTest.regionSampler
+ }
+ }
+
+ Assert.assertEquals(regionSamplingInstance.regionSampler, null)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
new file mode 100644
index 0000000..9393a4f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.shared.rotation
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.Display
+import android.view.WindowInsetsController
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@RunWithLooper
+class RotationButtonControllerTest : SysuiTestCase() {
+
+ private lateinit var mController: RotationButtonController
+
+ @Before
+ fun setUp() {
+ mController = RotationButtonController(
+ mContext,
+ /* lightIconColor = */ 0,
+ /* darkIconColor = */ 0,
+ /* iconCcwStart0ResId = */ 0,
+ /* iconCcwStart90ResId = */ 0,
+ /* iconCwStart0ResId = */ 0,
+ /* iconCwStart90ResId = */ 0
+ ) { 0 }
+ }
+
+ @Test
+ fun ifGestural_showRotationSuggestion() {
+ mController.onNavigationBarWindowVisibilityChange( /* showing = */ false)
+ mController.onBehaviorChanged(Display.DEFAULT_DISPLAY,
+ WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE)
+ mController.onNavigationModeChanged(WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON)
+ mController.onTaskbarStateChange( /* visible = */ false, /* stashed = */ false)
+ assertThat(mController.canShowRotationButton()).isFalse()
+
+ mController.onNavigationModeChanged(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL)
+
+ assertThat(mController.canShowRotationButton()).isTrue()
+ }
+
+ @Test
+ fun ifTaskbarVisible_showRotationSuggestion() {
+ mController.onNavigationBarWindowVisibilityChange( /* showing = */ false)
+ mController.onBehaviorChanged(Display.DEFAULT_DISPLAY,
+ WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE)
+ mController.onNavigationModeChanged(WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON)
+ mController.onTaskbarStateChange( /* visible = */ false, /* stashed = */ false)
+ assertThat(mController.canShowRotationButton()).isFalse()
+
+ mController.onTaskbarStateChange( /* visible = */ true, /* stashed = */ false)
+
+ assertThat(mController.canShowRotationButton()).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index be631af..1d8e5de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -38,8 +38,8 @@
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -89,8 +89,8 @@
val listener = mock(StatusBarStateController.StateListener::class.java)
controller.addCallback(listener)
- controller.setDozeAmount(0.5f, false /* animated */)
- controller.setDozeAmount(0.5f, false /* animated */)
+ controller.setAndInstrumentDozeAmount(null, 0.5f, false /* animated */)
+ controller.setAndInstrumentDozeAmount(null, 0.5f, false /* animated */)
verify(listener).onDozeAmountChanged(eq(0.5f), anyFloat())
}
@@ -135,7 +135,7 @@
@Test
fun testSetDozeAmount_immediatelyChangesDozeAmount_lockscreenTransitionFromAod() {
// Put controller in AOD state
- controller.setDozeAmount(1f, false)
+ controller.setAndInstrumentDozeAmount(null, 1f, false)
// When waking from doze, CentralSurfaces#updateDozingState will update the dozing state
// before the doze amount changes
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
index 64d0256..214ba16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
@@ -98,7 +98,7 @@
@Test
fun testPrepareDialogForApp_onlyDefaultChannel() {
- group.addChannel(channelDefault)
+ group.channels = listOf(channelDefault)
controller.prepareDialogForApp(TEST_APP_NAME, TEST_PACKAGE_NAME, TEST_UID,
setOf(channelDefault), appIcon, clickListener)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoProcessorTest.kt
deleted file mode 100644
index 515a7c9..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoProcessorTest.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline
-
-import android.net.NetworkCapabilities
-import android.testing.AndroidTestingRunner
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.pipeline.repository.NetworkCapabilityInfo
-import com.android.systemui.util.mockito.mock
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.CoroutineStart
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.InternalCoroutinesApi
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.yield
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.`when` as whenever
-
-@OptIn(InternalCoroutinesApi::class)
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-class ConnectivityInfoProcessorTest : SysuiTestCase() {
-
- private val statusBarPipelineFlags = mock<StatusBarPipelineFlags>()
-
- @Before
- fun setUp() {
- whenever(statusBarPipelineFlags.isNewPipelineEnabled()).thenReturn(true)
- }
-
- @Test
- fun collectorInfoUpdated_processedInfoAlsoUpdated() = runBlocking {
- // GIVEN a processor hooked up to a collector
- val scope = CoroutineScope(Dispatchers.Unconfined)
- val collector = FakeConnectivityInfoCollector()
- val processor = ConnectivityInfoProcessor(
- collector,
- context,
- scope,
- statusBarPipelineFlags,
- )
-
- var mostRecentValue: ProcessedConnectivityInfo? = null
- val job = launch(start = CoroutineStart.UNDISPATCHED) {
- processor.processedInfoFlow.collect {
- mostRecentValue = it
- }
- }
-
- // WHEN the collector emits a value
- val networkCapabilityInfo = mapOf(
- 10 to NetworkCapabilityInfo(mock(), NetworkCapabilities.Builder().build())
- )
- collector.emitValue(RawConnectivityInfo(networkCapabilityInfo))
- // Because our job uses [CoroutineStart.UNDISPATCHED], it executes in the same thread as
- // this test. So, our test needs to yield to let the job run.
- // Note: Once we upgrade our Kotlin coroutines testing library, we won't need this.
- yield()
-
- // THEN the processor receives it
- assertThat(mostRecentValue?.networkCapabilityInfo).isEqualTo(networkCapabilityInfo)
-
- job.cancel()
- scope.cancel()
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/FakeConnectivityInfoCollector.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/FakeConnectivityInfoCollector.kt
deleted file mode 100644
index 710e5f6..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/FakeConnectivityInfoCollector.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline
-
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
-
-/**
- * A test-friendly implementation of [ConnectivityInfoCollector] that just emits whatever value it
- * receives in [emitValue].
- */
-class FakeConnectivityInfoCollector : ConnectivityInfoCollector {
- private val _rawConnectivityInfoFlow = MutableStateFlow(RawConnectivityInfo())
- override val rawConnectivityInfoFlow = _rawConnectivityInfoFlow.asStateFlow()
-
- suspend fun emitValue(value: RawConnectivityInfo) {
- _rawConnectivityInfoFlow.emit(value)
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/repository/NetworkCapabilitiesRepoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/repository/NetworkCapabilitiesRepoTest.kt
deleted file mode 100644
index 40f8fbf..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/repository/NetworkCapabilitiesRepoTest.kt
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.repository
-
-import android.net.ConnectivityManager
-import android.net.ConnectivityManager.NetworkCallback
-import android.net.Network
-import android.net.NetworkCapabilities
-import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED
-import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
-import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
-import android.net.NetworkCapabilities.TRANSPORT_WIFI
-import android.net.NetworkRequest
-import android.test.suitebuilder.annotation.SmallTest
-import android.testing.AndroidTestingRunner
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.pipeline.ConnectivityPipelineLogger
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.withArgCaptor
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.CoroutineStart
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
-import org.mockito.MockitoAnnotations
-
-// TODO(b/240619365): Update this test to use `runTest` when we update the testing library
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-class NetworkCapabilitiesRepoTest : SysuiTestCase() {
- @Mock private lateinit var connectivityManager: ConnectivityManager
- @Mock private lateinit var logger: ConnectivityPipelineLogger
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- }
-
- @Test
- fun testOnCapabilitiesChanged_oneNewNetwork_networkStored() = runBlocking {
- // GIVEN a repo hooked up to [ConnectivityManager]
- val scope = CoroutineScope(Dispatchers.Unconfined)
- val repo = NetworkCapabilitiesRepo(
- connectivityManager = connectivityManager,
- scope = scope,
- logger = logger,
- )
-
- val job = launch(start = CoroutineStart.UNDISPATCHED) {
- repo.dataStream.collect {
- }
- }
-
- val callback: NetworkCallback = withArgCaptor {
- verify(connectivityManager)
- .registerNetworkCallback(any(NetworkRequest::class.java), capture())
- }
-
- // WHEN a new network is added
- callback.onCapabilitiesChanged(NET_1, NET_1_CAPS)
-
- val currentMap = repo.dataStream.value
-
- // THEN it is emitted from the flow
- assertThat(currentMap[NET_1_ID]?.network).isEqualTo(NET_1)
- assertThat(currentMap[NET_1_ID]?.capabilities).isEqualTo(NET_1_CAPS)
-
- job.cancel()
- scope.cancel()
- }
-
- @Test
- fun testOnCapabilitiesChanged_twoNewNetworks_bothStored() = runBlocking {
- // GIVEN a repo hooked up to [ConnectivityManager]
- val scope = CoroutineScope(Dispatchers.Unconfined)
- val repo = NetworkCapabilitiesRepo(
- connectivityManager = connectivityManager,
- scope = scope,
- logger = logger,
- )
-
- val job = launch(start = CoroutineStart.UNDISPATCHED) {
- repo.dataStream.collect {
- }
- }
-
- val callback: NetworkCallback = withArgCaptor {
- verify(connectivityManager)
- .registerNetworkCallback(any(NetworkRequest::class.java), capture())
- }
-
- // WHEN two new networks are added
- callback.onCapabilitiesChanged(NET_1, NET_1_CAPS)
- callback.onCapabilitiesChanged(NET_2, NET_2_CAPS)
-
- val currentMap = repo.dataStream.value
-
- // THEN the current state of the flow reflects 2 networks
- assertThat(currentMap[NET_1_ID]?.network).isEqualTo(NET_1)
- assertThat(currentMap[NET_1_ID]?.capabilities).isEqualTo(NET_1_CAPS)
- assertThat(currentMap[NET_2_ID]?.network).isEqualTo(NET_2)
- assertThat(currentMap[NET_2_ID]?.capabilities).isEqualTo(NET_2_CAPS)
-
- job.cancel()
- scope.cancel()
- }
-
- @Test
- fun testOnCapabilitesChanged_newCapabilitiesForExistingNetwork_areCaptured() = runBlocking {
- // GIVEN a repo hooked up to [ConnectivityManager]
- val scope = CoroutineScope(Dispatchers.Unconfined)
- val repo = NetworkCapabilitiesRepo(
- connectivityManager = connectivityManager,
- scope = scope,
- logger = logger,
- )
-
- val job = launch(start = CoroutineStart.UNDISPATCHED) {
- repo.dataStream.collect {
- }
- }
-
- val callback: NetworkCallback = withArgCaptor {
- verify(connectivityManager)
- .registerNetworkCallback(any(NetworkRequest::class.java), capture())
- }
-
- // WHEN a network is added, and then its capabilities are changed
- callback.onCapabilitiesChanged(NET_1, NET_1_CAPS)
- callback.onCapabilitiesChanged(NET_1, NET_2_CAPS)
-
- val currentMap = repo.dataStream.value
-
- // THEN the current state of the flow reflects the new capabilities
- assertThat(currentMap[NET_1_ID]?.capabilities).isEqualTo(NET_2_CAPS)
-
- job.cancel()
- scope.cancel()
- }
-
- @Test
- fun testOnLost_networkIsRemoved() = runBlocking {
- // GIVEN a repo hooked up to [ConnectivityManager]
- val scope = CoroutineScope(Dispatchers.Unconfined)
- val repo = NetworkCapabilitiesRepo(
- connectivityManager = connectivityManager,
- scope = scope,
- logger = logger,
- )
-
- val job = launch(start = CoroutineStart.UNDISPATCHED) {
- repo.dataStream.collect {
- }
- }
-
- val callback: NetworkCallback = withArgCaptor {
- verify(connectivityManager)
- .registerNetworkCallback(any(NetworkRequest::class.java), capture())
- }
-
- // WHEN two new networks are added, and one is removed
- callback.onCapabilitiesChanged(NET_1, NET_1_CAPS)
- callback.onCapabilitiesChanged(NET_2, NET_2_CAPS)
- callback.onLost(NET_1)
-
- val currentMap = repo.dataStream.value
-
- // THEN the current state of the flow reflects only the remaining network
- assertThat(currentMap[NET_1_ID]).isNull()
- assertThat(currentMap[NET_2_ID]?.network).isEqualTo(NET_2)
- assertThat(currentMap[NET_2_ID]?.capabilities).isEqualTo(NET_2_CAPS)
-
- job.cancel()
- scope.cancel()
- }
-
- @Test
- fun testOnLost_noNetworks_doesNotCrash() = runBlocking {
- // GIVEN a repo hooked up to [ConnectivityManager]
- val scope = CoroutineScope(Dispatchers.Unconfined)
- val repo = NetworkCapabilitiesRepo(
- connectivityManager = connectivityManager,
- scope = scope,
- logger = logger,
- )
-
- val job = launch(start = CoroutineStart.UNDISPATCHED) {
- repo.dataStream.collect {
- }
- }
-
- val callback: NetworkCallback = withArgCaptor {
- verify(connectivityManager)
- .registerNetworkCallback(any(NetworkRequest::class.java), capture())
- }
-
- // WHEN no networks are added, and one is removed
- callback.onLost(NET_1)
-
- val currentMap = repo.dataStream.value
-
- // THEN the current state of the flow shows no networks
- assertThat(currentMap).isEmpty()
-
- job.cancel()
- scope.cancel()
- }
-
- private val NET_1_ID = 100
- private val NET_1 = mock<Network>().also {
- whenever(it.getNetId()).thenReturn(NET_1_ID)
- }
- private val NET_2_ID = 200
- private val NET_2 = mock<Network>().also {
- whenever(it.getNetId()).thenReturn(NET_2_ID)
- }
-
- private val NET_1_CAPS = NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_VALIDATED)
- .build()
-
- private val NET_2_CAPS = NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_VALIDATED)
- .build()
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ConnectivityPipelineLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ConnectivityPipelineLoggerTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
index 2915ae8..36be1be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ConnectivityPipelineLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline
+package com.android.systemui.statusbar.pipeline.shared
import android.net.Network
import android.net.NetworkCapabilities
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
new file mode 100644
index 0000000..6b8d4aa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.data.repository
+
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** Fake implementation of [WifiRepository] exposing set methods for all the flows. */
+class FakeWifiRepository : WifiRepository {
+ private val _wifiNetwork: MutableStateFlow<WifiNetworkModel> =
+ MutableStateFlow(WifiNetworkModel.Inactive)
+ override val wifiNetwork: Flow<WifiNetworkModel> = _wifiNetwork
+
+ private val _wifiActivity = MutableStateFlow(ACTIVITY_DEFAULT)
+ override val wifiActivity: Flow<WifiActivityModel> = _wifiActivity
+
+ fun setWifiNetwork(wifiNetworkModel: WifiNetworkModel) {
+ _wifiNetwork.value = wifiNetworkModel
+ }
+
+ fun setWifiActivity(activity: WifiActivityModel) {
+ _wifiActivity.value = activity
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
new file mode 100644
index 0000000..d0a3808
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.data.repository
+
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.vcn.VcnTransportInfo
+import android.net.wifi.WifiInfo
+import android.net.wifi.WifiManager
+import android.net.wifi.WifiManager.TrafficStateCallback
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Executor
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class WifiRepositoryImplTest : SysuiTestCase() {
+
+ private lateinit var underTest: WifiRepositoryImpl
+
+ @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var connectivityManager: ConnectivityManager
+ @Mock private lateinit var wifiManager: WifiManager
+ private lateinit var executor: Executor
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ executor = FakeExecutor(FakeSystemClock())
+
+ underTest = WifiRepositoryImpl(
+ connectivityManager,
+ wifiManager,
+ executor,
+ logger,
+ )
+ }
+
+ @Test
+ fun wifiNetwork_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isEqualTo(WIFI_NETWORK_DEFAULT)
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_primaryWifiNetworkAdded_flowHasNetwork() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ val wifiInfo = mock<WifiInfo>().apply {
+ whenever(this.ssid).thenReturn(SSID)
+ whenever(this.isPrimary).thenReturn(true)
+ }
+ val network = mock<Network>().apply {
+ whenever(this.getNetId()).thenReturn(NETWORK_ID)
+ }
+
+ getNetworkCallback().onCapabilitiesChanged(network, createWifiNetworkCapabilities(wifiInfo))
+
+ assertThat(latest is WifiNetworkModel.Active).isTrue()
+ val latestActive = latest as WifiNetworkModel.Active
+ assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
+ assertThat(latestActive.ssid).isEqualTo(SSID)
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_nonPrimaryWifiNetworkAdded_flowHasNoNetwork() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ val wifiInfo = mock<WifiInfo>().apply {
+ whenever(this.ssid).thenReturn(SSID)
+ whenever(this.isPrimary).thenReturn(false)
+ }
+
+ getNetworkCallback().onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
+
+ assertThat(latest is WifiNetworkModel.Inactive).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_cellularVcnNetworkAdded_flowHasNetwork() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ val capabilities = mock<NetworkCapabilities>().apply {
+ whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+ whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
+ }
+
+ getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
+
+ assertThat(latest is WifiNetworkModel.Active).isTrue()
+ val latestActive = latest as WifiNetworkModel.Active
+ assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
+ assertThat(latestActive.ssid).isEqualTo(SSID)
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_nonPrimaryCellularVcnNetworkAdded_flowHasNoNetwork() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ val wifiInfo = mock<WifiInfo>().apply {
+ whenever(this.ssid).thenReturn(SSID)
+ whenever(this.isPrimary).thenReturn(false)
+ }
+ val capabilities = mock<NetworkCapabilities>().apply {
+ whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+ whenever(this.transportInfo).thenReturn(VcnTransportInfo(wifiInfo))
+ }
+
+ getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
+
+ assertThat(latest is WifiNetworkModel.Inactive).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_cellularNotVcnNetworkAdded_flowHasNoNetwork() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ val capabilities = mock<NetworkCapabilities>().apply {
+ whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+ whenever(this.transportInfo).thenReturn(mock())
+ }
+
+ getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
+
+ assertThat(latest is WifiNetworkModel.Inactive).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_newPrimaryWifiNetwork_flowHasNewNetwork() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ // Start with the original network
+ getNetworkCallback()
+ .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
+
+ // WHEN we update to a new primary network
+ val newNetworkId = 456
+ val newNetwork = mock<Network>().apply {
+ whenever(this.getNetId()).thenReturn(newNetworkId)
+ }
+ val newSsid = "CD"
+ val newWifiInfo = mock<WifiInfo>().apply {
+ whenever(this.ssid).thenReturn(newSsid)
+ whenever(this.isPrimary).thenReturn(true)
+ }
+
+ getNetworkCallback().onCapabilitiesChanged(
+ newNetwork, createWifiNetworkCapabilities(newWifiInfo)
+ )
+
+ // THEN we use the new network
+ assertThat(latest is WifiNetworkModel.Active).isTrue()
+ val latestActive = latest as WifiNetworkModel.Active
+ assertThat(latestActive.networkId).isEqualTo(newNetworkId)
+ assertThat(latestActive.ssid).isEqualTo(newSsid)
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_newNonPrimaryWifiNetwork_flowHasOldNetwork() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ // Start with the original network
+ getNetworkCallback()
+ .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
+
+ // WHEN we notify of a new but non-primary network
+ val newNetworkId = 456
+ val newNetwork = mock<Network>().apply {
+ whenever(this.getNetId()).thenReturn(newNetworkId)
+ }
+ val newSsid = "EF"
+ val newWifiInfo = mock<WifiInfo>().apply {
+ whenever(this.ssid).thenReturn(newSsid)
+ whenever(this.isPrimary).thenReturn(false)
+ }
+
+ getNetworkCallback().onCapabilitiesChanged(
+ newNetwork, createWifiNetworkCapabilities(newWifiInfo)
+ )
+
+ // THEN we still use the original network
+ assertThat(latest is WifiNetworkModel.Active).isTrue()
+ val latestActive = latest as WifiNetworkModel.Active
+ assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
+ assertThat(latestActive.ssid).isEqualTo(SSID)
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_newNetworkCapabilities_flowHasNewData() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ val wifiInfo = mock<WifiInfo>().apply {
+ whenever(this.ssid).thenReturn(SSID)
+ whenever(this.isPrimary).thenReturn(true)
+ }
+
+ // Start with the original network
+ getNetworkCallback()
+ .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo))
+
+ // WHEN we keep the same network ID but change the SSID
+ val newSsid = "CD"
+ val newWifiInfo = mock<WifiInfo>().apply {
+ whenever(this.ssid).thenReturn(newSsid)
+ whenever(this.isPrimary).thenReturn(true)
+ }
+
+ getNetworkCallback()
+ .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(newWifiInfo))
+
+ // THEN we've updated to the new SSID
+ assertThat(latest is WifiNetworkModel.Active).isTrue()
+ val latestActive = latest as WifiNetworkModel.Active
+ assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
+ assertThat(latestActive.ssid).isEqualTo(newSsid)
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_noCurrentNetwork_networkLost_flowHasNoNetwork() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ // WHEN we receive #onLost without any #onCapabilitiesChanged beforehand
+ getNetworkCallback().onLost(NETWORK)
+
+ // THEN there's no crash and we still have no network
+ assertThat(latest is WifiNetworkModel.Inactive).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_currentNetworkLost_flowHasNoNetwork() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ getNetworkCallback()
+ .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
+ assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(NETWORK_ID)
+
+ // WHEN we lose our current network
+ getNetworkCallback().onLost(NETWORK)
+
+ // THEN we update to no network
+ assertThat(latest is WifiNetworkModel.Inactive).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_unknownNetworkLost_flowHasPreviousNetwork() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ getNetworkCallback()
+ .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
+ assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(NETWORK_ID)
+
+ // WHEN we lose an unknown network
+ val unknownNetwork = mock<Network>().apply {
+ whenever(this.getNetId()).thenReturn(543)
+ }
+ getNetworkCallback().onLost(unknownNetwork)
+
+ // THEN we still have our previous network
+ assertThat(latest is WifiNetworkModel.Active).isTrue()
+ val latestActive = latest as WifiNetworkModel.Active
+ assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
+ assertThat(latestActive.ssid).isEqualTo(SSID)
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiNetwork_notCurrentNetworkLost_flowHasCurrentNetwork() = runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ getNetworkCallback()
+ .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
+ assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(NETWORK_ID)
+
+ // WHEN we update to a new network...
+ val newNetworkId = 89
+ val newNetwork = mock<Network>().apply {
+ whenever(this.getNetId()).thenReturn(newNetworkId)
+ }
+ getNetworkCallback().onCapabilitiesChanged(
+ newNetwork, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)
+ )
+ // ...and lose the old network
+ getNetworkCallback().onLost(NETWORK)
+
+ // THEN we still have the new network
+ assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(newNetworkId)
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiActivity_nullWifiManager_receivesDefault() = runBlocking(IMMEDIATE) {
+ underTest = WifiRepositoryImpl(
+ connectivityManager,
+ wifiManager = null,
+ executor,
+ logger,
+ )
+
+ var latest: WifiActivityModel? = null
+ val job = underTest
+ .wifiActivity
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isEqualTo(ACTIVITY_DEFAULT)
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiActivity_callbackGivesNone_activityFlowHasNone() = runBlocking(IMMEDIATE) {
+ var latest: WifiActivityModel? = null
+ val job = underTest
+ .wifiActivity
+ .onEach { latest = it }
+ .launchIn(this)
+
+ getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_NONE)
+
+ assertThat(latest).isEqualTo(
+ WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiActivity_callbackGivesIn_activityFlowHasIn() = runBlocking(IMMEDIATE) {
+ var latest: WifiActivityModel? = null
+ val job = underTest
+ .wifiActivity
+ .onEach { latest = it }
+ .launchIn(this)
+
+ getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_IN)
+
+ assertThat(latest).isEqualTo(
+ WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiActivity_callbackGivesOut_activityFlowHasOut() = runBlocking(IMMEDIATE) {
+ var latest: WifiActivityModel? = null
+ val job = underTest
+ .wifiActivity
+ .onEach { latest = it }
+ .launchIn(this)
+
+ getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_OUT)
+
+ assertThat(latest).isEqualTo(
+ WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
+ )
+
+ job.cancel()
+ }
+
+ @Test
+ fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() = runBlocking(IMMEDIATE) {
+ var latest: WifiActivityModel? = null
+ val job = underTest
+ .wifiActivity
+ .onEach { latest = it }
+ .launchIn(this)
+
+ getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_INOUT)
+
+ assertThat(latest).isEqualTo(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+
+ job.cancel()
+ }
+
+ private fun getTrafficStateCallback(): TrafficStateCallback {
+ val callbackCaptor = argumentCaptor<TrafficStateCallback>()
+ verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
+ return callbackCaptor.value!!
+ }
+
+ private fun getNetworkCallback(): ConnectivityManager.NetworkCallback {
+ val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
+ verify(connectivityManager).registerNetworkCallback(any(), callbackCaptor.capture())
+ return callbackCaptor.value!!
+ }
+
+ private fun createWifiNetworkCapabilities(wifiInfo: WifiInfo) =
+ mock<NetworkCapabilities>().apply {
+ whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+ whenever(this.transportInfo).thenReturn(wifiInfo)
+ }
+
+ private companion object {
+ const val NETWORK_ID = 45
+ val NETWORK = mock<Network>().apply {
+ whenever(this.getNetId()).thenReturn(NETWORK_ID)
+ }
+ const val SSID = "AB"
+ val PRIMARY_WIFI_INFO: WifiInfo = mock<WifiInfo>().apply {
+ whenever(this.ssid).thenReturn(SSID)
+ whenever(this.isPrimary).thenReturn(true)
+ }
+ }
+}
+
+private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
new file mode 100644
index 0000000..5f1b1db
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
+import org.junit.Before
+import org.junit.Test
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class WifiInteractorTest : SysuiTestCase() {
+
+ private lateinit var underTest: WifiInteractor
+
+ private lateinit var repository: FakeWifiRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeWifiRepository()
+ underTest = WifiInteractor(repository)
+ }
+
+ @Test
+ fun hasActivityIn_noInOrOut_outputsFalse() = runBlocking(IMMEDIATE) {
+ repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
+
+ var latest: Boolean? = null
+ val job = underTest
+ .hasActivityIn
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun hasActivityIn_onlyOut_outputsFalse() = runBlocking(IMMEDIATE) {
+ repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
+
+ var latest: Boolean? = null
+ val job = underTest
+ .hasActivityIn
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun hasActivityIn_onlyIn_outputsTrue() = runBlocking(IMMEDIATE) {
+ repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+
+ var latest: Boolean? = null
+ val job = underTest
+ .hasActivityIn
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun hasActivityIn_inAndOut_outputsTrue() = runBlocking(IMMEDIATE) {
+ repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+
+ var latest: Boolean? = null
+ val job = underTest
+ .hasActivityIn
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun hasActivityIn_ssidNull_outputsFalse() = runBlocking(IMMEDIATE) {
+ repository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = null))
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+
+ var latest: Boolean? = null
+ val job = underTest
+ .hasActivityIn
+ .onEach { latest = it }
+ .launchIn(this)
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun hasActivityIn_multipleChanges_multipleOutputChanges() = runBlocking(IMMEDIATE) {
+ repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+
+ var latest: Boolean? = null
+ val job = underTest
+ .hasActivityIn
+ .onEach { latest = it }
+ .launchIn(this)
+
+ // Conduct a series of changes and verify we catch each of them in succession
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+ yield()
+ assertThat(latest).isTrue()
+
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
+ yield()
+ assertThat(latest).isFalse()
+
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+ yield()
+ assertThat(latest).isTrue()
+
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+ yield()
+ assertThat(latest).isTrue()
+
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
+ yield()
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ companion object {
+ val VALID_WIFI_NETWORK_MODEL = WifiNetworkModel.Active(networkId = 1, ssid = "AB")
+ }
+}
+
+private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
new file mode 100644
index 0000000..fae4b105
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
+import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class WifiViewModelTest : SysuiTestCase() {
+
+ private lateinit var underTest: WifiViewModel
+
+ @Mock private lateinit var logger: ConnectivityPipelineLogger
+ @Mock private lateinit var constants: WifiConstants
+ private lateinit var repository: FakeWifiRepository
+ private lateinit var interactor: WifiInteractor
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ repository = FakeWifiRepository()
+ interactor = WifiInteractor(repository)
+
+ underTest = WifiViewModel(
+ constants,
+ logger,
+ interactor
+ )
+
+ // Set up with a valid SSID
+ repository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = "AB"))
+ }
+
+ @Test
+ fun activityInVisible_showActivityConfigFalse_receivesFalse() = runBlocking(IMMEDIATE) {
+ whenever(constants.shouldShowActivityConfig).thenReturn(false)
+
+ var latest: Boolean? = null
+ val job = underTest
+ .isActivityInVisible
+ .onEach { latest = it }
+ .launchIn(this)
+
+ // Verify that on launch, we receive a false.
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun activityInVisible_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
+ whenever(constants.shouldShowActivityConfig).thenReturn(false)
+
+ var latest: Boolean? = null
+ val job = underTest
+ .isActivityInVisible
+ .onEach { latest = it }
+ .launchIn(this)
+
+ // Update the repo to have activityIn
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+ yield()
+
+ // Verify that we didn't update to activityIn=true (because our config is false)
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun activityInVisible_showActivityConfigTrue_receivesUpdate() = runBlocking(IMMEDIATE) {
+ whenever(constants.shouldShowActivityConfig).thenReturn(true)
+
+ var latest: Boolean? = null
+ val job = underTest
+ .isActivityInVisible
+ .onEach { latest = it }
+ .launchIn(this)
+
+ // Update the repo to have activityIn
+ repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+ yield()
+
+ // Verify that we updated to activityIn=true
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+}
+
+private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index b7f38f1..50259b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -310,7 +310,7 @@
}
@Test
- public void onWallpaperColorsChanged_ResetThemeWithNewHomeWallpapers() {
+ public void onWallpaperColorsChanged_resetThemeWithNewHomeWallpapers() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
@@ -345,6 +345,61 @@
}
@Test
+ public void onWallpaperColorsChanged_keepsThemeWhenSetFromLockScreen() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+ String jsonString =
+ "{\"android.theme.customization.color_source\":\"lock_wallpaper\","
+ + "\"android.theme.customization.system_palette\":\"A16B00\","
+ + "\"android.theme.customization.accent_color\":\"A16B00\","
+ + "\"android.theme.customization.color_index\":\"2\"}";
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(20);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM))
+ .thenReturn(21);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
+ verify(mSecureSettings, never()).putStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), any(), anyInt());
+ }
+
+ @Test
+ public void onWallpaperColorsChanged_resetLockScreenThemeWhenBothSet() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+ String jsonString =
+ "{\"android.theme.customization.color_source\":\"lock_wallpaper\","
+ + "\"android.theme.customization.system_palette\":\"A16B00\","
+ + "\"android.theme.customization.accent_color\":\"A16B00\","
+ + "\"android.theme.customization.color_index\":\"2\"}";
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(20);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM))
+ .thenReturn(21);
+
+ mColorsListener.getValue().onColorsChanged(mainColors,
+ WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK,
+ USER_SYSTEM);
+
+ ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
+ verify(mSecureSettings).putStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture(),
+ anyInt());
+ assertThat(updatedSetting.getValue().contains(
+ "android.theme.customization.color_both\":\"1")).isTrue();
+ verify(mThemeOverlayApplier)
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+ @Test
public void onSettingChanged_honorThemeStyle() {
when(mDeviceProvisionedController.isUserSetup(anyInt())).thenReturn(true);
List<Style> validStyles = Arrays.asList(Style.EXPRESSIVE, Style.SPRITZ, Style.TONAL_SPOT,
@@ -381,7 +436,7 @@
}
@Test
- public void onWallpaperColorsChanged_ResetThemeWithNewHomeAndLockWallpaper() {
+ public void onWallpaperColorsChanged_resetThemeWithNewHomeAndLockWallpaper() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
@@ -450,7 +505,7 @@
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
String jsonString =
- "{\"android.theme.customization.color_source\":\"lock_wallpaper\","
+ "{\"android.theme.customization.color_source\":\"home_wallpaper\","
+ "\"android.theme.customization.system_palette\":\"A16B00\","
+ "\"android.theme.customization.accent_color\":\"A16B00\","
+ "\"android.theme.customization.color_index\":\"2\"}";
@@ -476,7 +531,7 @@
}
@Test
- public void onWallpaperColorsChanged_ResetThemeWhenFromLatestWallpaper() {
+ public void onWallpaperColorsChanged_resetThemeWhenFromLatestWallpaper() {
// Should ask for a new theme when the colors of the last applied wallpaper change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index d0c87e8..14220cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -63,6 +63,7 @@
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.PowerManager;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.dreams.IDreamManager;
@@ -204,6 +205,8 @@
private ArgumentCaptor<IntentFilter> mFilterArgumentCaptor;
@Captor
private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor;
+ @Captor
+ private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallbackCaptor;
private BubblesManager mBubblesManager;
private TestableBubbleController mBubbleController;
@@ -240,6 +243,8 @@
@Mock
private IStatusBarService mStatusBarService;
@Mock
+ private IDreamManager mIDreamManager;
+ @Mock
private NotificationVisibilityProvider mVisibilityProvider;
@Mock
private LauncherApps mLauncherApps;
@@ -371,10 +376,11 @@
mContext,
mBubbleController.asBubbles(),
mNotificationShadeWindowController,
- mock(KeyguardStateController.class),
+ mKeyguardStateController,
mShadeController,
mStatusBarService,
mock(INotificationManager.class),
+ mIDreamManager,
mVisibilityProvider,
interruptionStateProvider,
mZenModeController,
@@ -391,6 +397,25 @@
verify(mNotifPipeline, atLeastOnce())
.addCollectionListener(mNotifListenerCaptor.capture());
mEntryListener = mNotifListenerCaptor.getValue();
+
+ // Get a reference to KeyguardStateController.Callback
+ verify(mKeyguardStateController, atLeastOnce())
+ .addCallback(mKeyguardStateControllerCallbackCaptor.capture());
+ }
+
+ @Test
+ public void dreamingHidesBubbles() throws RemoteException {
+ mBubbleController.updateBubble(mBubbleEntry);
+ assertTrue(mBubbleController.hasBubbles());
+ assertThat(mBubbleController.getStackView().getVisibility()).isEqualTo(View.VISIBLE);
+
+ when(mIDreamManager.isDreamingOrInPreview()).thenReturn(true); // dreaming is happening
+ when(mKeyguardStateController.isShowing()).thenReturn(false); // device is unlocked
+ KeyguardStateController.Callback callback =
+ mKeyguardStateControllerCallbackCaptor.getValue();
+ callback.onKeyguardShowingChanged();
+
+ assertThat(mBubbleController.getStackView().getVisibility()).isEqualTo(View.INVISIBLE);
}
@Test
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
index 309acdf..f539dbd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
@@ -91,6 +91,8 @@
fun capture(): T = wrapped.capture()
val value: T
get() = wrapped.value
+ val allValues: List<T>
+ get() = wrapped.allValues
}
/**
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 0a4ecb2..5154a2d 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -298,6 +298,10 @@
// Notify the user to setup their dock
NOTE_SETUP_DOCK = 72;
+ // Inform the user of bluetooth apm state changes.
+ // Package: android
+ NOTE_BT_APM_NOTIFICATION = 74;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
index 23cded7..35a1508 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
@@ -193,6 +193,6 @@
@Override
public String toString() {
return "MagnificationGesturesObserver{"
- + ", mDelayedEventQueue=" + mDelayedEventQueue + '}';
+ + "mDelayedEventQueue=" + mDelayedEventQueue + '}';
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 9ff51ee..cf30a5a 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -28,12 +28,14 @@
import android.annotation.UiContext;
import android.content.Context;
import android.graphics.Point;
+import android.os.SystemClock;
import android.provider.Settings;
import android.util.MathUtils;
import android.util.Slog;
import android.view.Display;
import android.view.MotionEvent;
+import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.EventStreamTransformation;
@@ -91,6 +93,8 @@
private final Context mContext;
private final Point mTempPoint = new Point();
+ private long mTripleTapAndHoldStartedTime = 0;
+
public WindowMagnificationGestureHandler(@UiContext Context context,
WindowMagnificationManager windowMagnificationMgr,
AccessibilityTraceManager trace,
@@ -213,15 +217,39 @@
WindowMagnificationManager.WINDOW_POSITION_AT_CENTER);
}
- private void onTripleTapAndHold(MotionEvent up) {
+ @VisibleForTesting
+ void onTripleTapAndHold(MotionEvent up) {
if (DEBUG_DETECTING) {
Slog.i(mLogTag, "onTripleTapAndHold()");
}
enableWindowMagnifier(up.getX(), up.getY(),
WindowMagnificationManager.WINDOW_POSITION_AT_TOP_LEFT);
+ mTripleTapAndHoldStartedTime = SystemClock.uptimeMillis();
transitionTo(mViewportDraggingState);
}
+ @VisibleForTesting
+ void releaseTripleTapAndHold() {
+ mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
+ transitionTo(mDetectingState);
+ if (mTripleTapAndHoldStartedTime != 0) {
+ final long duration = SystemClock.uptimeMillis() - mTripleTapAndHoldStartedTime;
+ logMagnificationTripleTapAndHoldSession(duration);
+ mTripleTapAndHoldStartedTime = 0;
+ }
+ }
+
+ /**
+ * Logs the duration for the magnification session which is activated by the triple tap and
+ * hold gesture.
+ *
+ * @param duration The duration of a triple-tap-and-hold activation session.
+ */
+ @VisibleForTesting
+ void logMagnificationTripleTapAndHoldSession(long duration) {
+ AccessibilityStatsLogUtils.logMagnificationTripleTapAndHoldSession(duration);
+ }
+
void resetToDetectState() {
transitionTo(mDetectingState);
}
@@ -310,7 +338,7 @@
@Override
public String toString() {
return "PanningScalingState{"
- + "mPanningScalingHandler =" + mPanningScalingHandler + '}';
+ + "mPanningScalingHandler=" + mPanningScalingHandler + '}';
}
}
@@ -370,8 +398,7 @@
case ACTION_UP:
case ACTION_CANCEL: {
- mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
- transitionTo(mDetectingState);
+ releaseTripleTapAndHold();
}
break;
}
@@ -447,7 +474,7 @@
@Override
public String toString() {
return "DetectingState{"
- + ", mGestureTimeoutObserver =" + mGesturesObserver
+ + "mGestureTimeoutObserver=" + mGesturesObserver
+ '}';
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index ca116e3..09c6ca3 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -45,6 +45,7 @@
import android.view.accessibility.IWindowMagnificationConnectionCallback;
import android.view.accessibility.MagnificationAnimationCallback;
+import com.android.internal.accessibility.util.AccessibilityStatsLogUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
@@ -54,6 +55,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
/**
* A class to manipulate window magnification through {@link WindowMagnificationConnectionWrapper}
@@ -136,6 +138,7 @@
private SparseArray<WindowMagnifier> mWindowMagnifiers = new SparseArray<>();
// Whether the following typing focus feature for magnification is enabled.
private boolean mMagnificationFollowTypingEnabled = true;
+ @GuardedBy("mLock")
private final SparseBooleanArray mIsImeVisibleArray = new SparseBooleanArray();
private boolean mReceiverRegistered = false;
@@ -465,18 +468,43 @@
}
}
+ private void pauseTrackingTypingFocusRecord(int displayId) {
+ WindowMagnifier magnifier;
+ synchronized (mLock) {
+ magnifier = mWindowMagnifiers.get(displayId);
+ if (magnifier == null) {
+ return;
+ }
+ }
+ magnifier.pauseTrackingTypingFocusRecord();
+ }
+
/**
* Called when the IME window visibility changed.
*
* @param shown {@code true} means the IME window shows on the screen. Otherwise, it's hidden.
*/
void onImeWindowVisibilityChanged(int displayId, boolean shown) {
- mIsImeVisibleArray.put(displayId, shown);
+ synchronized (mLock) {
+ mIsImeVisibleArray.put(displayId, shown);
+ }
if (shown) {
enableAllTrackingTypingFocus();
+ } else {
+ pauseTrackingTypingFocusRecord(displayId);
}
}
+ boolean isImeVisible(int displayId) {
+ synchronized (mLock) {
+ return mIsImeVisibleArray.get(displayId);
+ }
+ }
+
+ void logTrackingTypingFocus(long duration) {
+ AccessibilityStatsLogUtils.logMagnificationFollowTypingFocusSession(duration);
+ }
+
@Override
public boolean processScroll(int displayId, float distanceX, float distanceY) {
moveWindowMagnification(displayId, -distanceX, -distanceY);
@@ -969,6 +997,12 @@
private boolean mTrackingTypingFocusEnabled = true;
+ private volatile long mTrackingTypingFocusStartTime = 0;
+ private static final AtomicLongFieldUpdater<WindowMagnifier> SUM_TIME_UPDATER =
+ AtomicLongFieldUpdater.newUpdater(WindowMagnifier.class,
+ "mTrackingTypingFocusSumTime");
+ private volatile long mTrackingTypingFocusSumTime = 0;
+
WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) {
mDisplayId = displayId;
mWindowMagnificationManager = windowMagnificationManager;
@@ -1017,6 +1051,7 @@
mEnabled = false;
mIdOfLastServiceToControl = INVALID_SERVICE_ID;
mTrackingTypingFocusEnabled = false;
+ pauseTrackingTypingFocusRecord();
return true;
}
return false;
@@ -1069,6 +1104,14 @@
}
void setTrackingTypingFocusEnabled(boolean trackingTypingFocusEnabled) {
+ if (mWindowMagnificationManager.isWindowMagnifierEnabled(mDisplayId)
+ && mWindowMagnificationManager.isImeVisible(mDisplayId)
+ && trackingTypingFocusEnabled) {
+ startTrackingTypingFocusRecord();
+ }
+ if (mTrackingTypingFocusEnabled && !trackingTypingFocusEnabled) {
+ stopAndLogTrackingTypingFocusRecordIfNeeded();
+ }
mTrackingTypingFocusEnabled = trackingTypingFocusEnabled;
}
@@ -1076,6 +1119,44 @@
return mTrackingTypingFocusEnabled;
}
+ void startTrackingTypingFocusRecord() {
+ if (mTrackingTypingFocusStartTime == 0) {
+ mTrackingTypingFocusStartTime = SystemClock.uptimeMillis();
+ if (DBG) {
+ Slog.d(TAG, "start: mTrackingTypingFocusStartTime = "
+ + mTrackingTypingFocusStartTime);
+ }
+ }
+ }
+
+ void pauseTrackingTypingFocusRecord() {
+ if (mTrackingTypingFocusStartTime != 0) {
+ final long elapsed = (SystemClock.uptimeMillis() - mTrackingTypingFocusStartTime);
+ // update mTrackingTypingFocusSumTime value in an atomic operation
+ SUM_TIME_UPDATER.addAndGet(this, elapsed);
+ mTrackingTypingFocusStartTime = 0;
+ if (DBG) {
+ Slog.d(TAG, "pause: mTrackingTypingFocusSumTime = "
+ + mTrackingTypingFocusSumTime + ", elapsed = " + elapsed);
+ }
+ }
+ }
+
+ void stopAndLogTrackingTypingFocusRecordIfNeeded() {
+ if (mTrackingTypingFocusStartTime != 0 || mTrackingTypingFocusSumTime != 0) {
+ final long elapsed = mTrackingTypingFocusStartTime != 0
+ ? (SystemClock.uptimeMillis() - mTrackingTypingFocusStartTime) : 0;
+ final long duration = mTrackingTypingFocusSumTime + elapsed;
+ if (DBG) {
+ Slog.d(TAG, "stop and log: session duration = " + duration
+ + ", elapsed = " + elapsed);
+ }
+ mWindowMagnificationManager.logTrackingTypingFocus(duration);
+ mTrackingTypingFocusStartTime = 0;
+ mTrackingTypingFocusSumTime = 0;
+ }
+ }
+
boolean isEnabled() {
return mEnabled;
}
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 43e2b88..593a63c 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -77,6 +77,14 @@
new ComponentName("android", BlockedAppStreamingActivity.class.getName());
/**
+ * For communicating when a secure window shows on the virtual display.
+ */
+ public interface SecureWindowCallback {
+ /** Called when a secure window shows on the virtual display. */
+ void onSecureWindowShown(int displayId, int uid);
+ }
+
+ /**
* If required, allow the secure activity to display on remote device since
* {@link android.os.Build.VERSION_CODES#TIRAMISU}.
*/
@@ -108,6 +116,7 @@
new ArraySet<>();
@Nullable
private final @AssociationRequest.DeviceProfile String mDeviceProfile;
+ @Nullable private final SecureWindowCallback mSecureWindowCallback;
/**
* Creates a window policy controller that is generic to the different use cases of virtual
@@ -131,6 +140,8 @@
* @param activityListener Activity listener to listen for activity changes.
* @param activityBlockedCallback Callback that is called when an activity is blocked from
* launching.
+ * @param secureWindowCallback Callback that is called when a secure window shows on the
+ * virtual display.
* @param deviceProfile The {@link AssociationRequest.DeviceProfile} of this virtual device.
*/
public GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
@@ -142,6 +153,7 @@
@ActivityPolicy int defaultActivityPolicy,
@NonNull ActivityListener activityListener,
@NonNull ActivityBlockedCallback activityBlockedCallback,
+ @NonNull SecureWindowCallback secureWindowCallback,
@AssociationRequest.DeviceProfile String deviceProfile) {
super();
mAllowedUsers = allowedUsers;
@@ -154,6 +166,7 @@
setInterestedWindowFlags(windowFlags, systemWindowFlags);
mActivityListener = activityListener;
mDeviceProfile = deviceProfile;
+ mSecureWindowCallback = secureWindowCallback;
}
/**
@@ -234,6 +247,12 @@
@Override
public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
int systemWindowFlags) {
+ // The callback is fired only when windowFlags are changed. To let VirtualDevice owner
+ // aware that the virtual display has a secure window on top.
+ if ((windowFlags & FLAG_SECURE) != 0) {
+ mSecureWindowCallback.onSecureWindowShown(mDisplayId, activityInfo.applicationInfo.uid);
+ }
+
if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
return false;
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 5f337ab..cca3212 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -52,6 +52,7 @@
import android.hardware.input.VirtualTouchEvent;
import android.os.Binder;
import android.os.IBinder;
+import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -542,6 +543,7 @@
mParams.getDefaultActivityPolicy(),
createListenerAdapter(),
this::onActivityBlocked,
+ this::onSecureWindowShown,
mAssociationInfo.getDeviceProfile());
gwpc.registerRunningAppsChangedListener(/* listener= */ this);
return gwpc;
@@ -591,6 +593,21 @@
mContext.getUser());
}
+ private void onSecureWindowShown(int displayId, int uid) {
+ if (!mVirtualDisplayIds.contains(displayId)) {
+ return;
+ }
+
+ // If a virtual display isn't secure, the screen can't be captured. Show a warning toast
+ // if the secure window is shown on a non-secure virtual display.
+ DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+ Display display = displayManager.getDisplay(displayId);
+ if ((display.getFlags() & FLAG_SECURE) == 0) {
+ showToastWhereUidIsRunning(uid, com.android.internal.R.string.vdm_secure_window,
+ Toast.LENGTH_LONG, mContext.getMainLooper());
+ }
+ }
+
private ArraySet<UserHandle> getAllowedUserHandles() {
ArraySet<UserHandle> result = new ArraySet<>();
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
@@ -650,14 +667,16 @@
/**
* Shows a toast on virtual displays owned by this device which have a given uid running.
*/
- void showToastWhereUidIsRunning(int uid, @StringRes int resId, @Toast.Duration int duration) {
- showToastWhereUidIsRunning(uid, mContext.getString(resId), duration);
+ void showToastWhereUidIsRunning(int uid, @StringRes int resId, @Toast.Duration int duration,
+ Looper looper) {
+ showToastWhereUidIsRunning(uid, mContext.getString(resId), duration, looper);
}
/**
* Shows a toast on virtual displays owned by this device which have a given uid running.
*/
- void showToastWhereUidIsRunning(int uid, String text, @Toast.Duration int duration) {
+ void showToastWhereUidIsRunning(int uid, String text, @Toast.Duration int duration,
+ Looper looper) {
synchronized (mVirtualDeviceLock) {
DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
final int size = mWindowPolicyControllers.size();
@@ -666,7 +685,7 @@
int displayId = mWindowPolicyControllers.keyAt(i);
Display display = displayManager.getDisplay(displayId);
if (display != null && display.isValid()) {
- Toast.makeText(mContext.createDisplayContext(display), text,
+ Toast.makeText(mContext.createDisplayContext(display), looper, text,
duration).show();
}
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 35e9060..41b6fad 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -202,7 +202,7 @@
getContext().getString(
com.android.internal.R.string.vdm_camera_access_denied,
deviceName),
- Toast.LENGTH_LONG);
+ Toast.LENGTH_LONG, Looper.myLooper());
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 07a5fb5..b512cdf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14255,10 +14255,12 @@
if (oldRecord.resultTo != null) {
final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
try {
+ oldRecord.mIsReceiverAppRunning = true;
oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
oldRecord.intent,
Activity.RESULT_CANCELED, null, null,
- false, false, oldRecord.userId, oldRecord.callingUid, callingUid);
+ false, false, oldRecord.userId, oldRecord.callingUid, callingUid,
+ SystemClock.uptimeMillis() - oldRecord.enqueueTime, 0);
} catch (RemoteException e) {
Slog.w(TAG, "Failure ["
+ queue.mQueueName + "] sending broadcast result of "
@@ -17385,7 +17387,8 @@
// sends to the activity. After this race issue between WM/ATMS and AMS is solved, this
// workaround can be removed. (b/213288355)
if (isNewPending) {
- mOomAdjuster.mCachedAppOptimizer.unfreezeProcess(pid);
+ mOomAdjuster.mCachedAppOptimizer.unfreezeProcess(pid,
+ OomAdjuster.OOM_ADJ_REASON_ACTIVITY);
}
// We need to update the network rules for the app coming to the top state so that
// it can access network when the device or the app is in a restricted state
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 43d0de9..5856949 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -36,6 +36,8 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
+import static com.android.server.am.OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER;
+import static com.android.server.am.OomAdjuster.OOM_ADJ_REASON_START_RECEIVER;
import android.annotation.NonNull;
@@ -321,7 +323,7 @@
}
private final void processCurBroadcastLocked(BroadcastRecord r,
- ProcessRecord app, int receiverType, int processTemperature) throws RemoteException {
+ ProcessRecord app) throws RemoteException {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " for app " + app);
final IApplicationThread thread = app.getThread();
@@ -347,7 +349,7 @@
// Force an update, even if there are other pending requests, overall it still saves time,
// because time(updateOomAdj(N apps)) <= N * time(updateOomAdj(1 app)).
mService.enqueueOomAdjTargetLocked(app);
- mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
+ mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_RECEIVER);
// Tell the application to launch this receiver.
maybeReportBroadcastDispatchedEventLocked(r, r.curReceiver.applicationInfo.uid);
@@ -367,10 +369,6 @@
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " DELIVERED for app " + app);
started = true;
- FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED, app.uid,
- r.callingUid == -1 ? Process.SYSTEM_UID : r.callingUid,
- ActivityManagerService.getShortAction(r.intent.getAction()),
- receiverType, processTemperature);
} finally {
if (!started) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
@@ -407,9 +405,8 @@
}
try {
mPendingBroadcast = null;
- processCurBroadcastLocked(br, app,
- BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST,
- BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD);
+ br.mIsReceiverAppRunning = false;
+ processCurBroadcastLocked(br, app);
didSomething = true;
} catch (Exception e) {
Slog.w(TAG, "Exception in new application when starting receiver "
@@ -517,6 +514,22 @@
final long finishTime = SystemClock.uptimeMillis();
final long elapsed = finishTime - r.receiverTime;
r.state = BroadcastRecord.IDLE;
+ final int curIndex = r.nextReceiver - 1;
+ if (curIndex >= 0 && curIndex < r.receivers.size() && r.curApp != null) {
+ final Object curReceiver = r.receivers.get(curIndex);
+ FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED, r.curApp.uid,
+ r.callingUid == -1 ? Process.SYSTEM_UID : r.callingUid,
+ ActivityManagerService.getShortAction(r.intent.getAction()),
+ curReceiver instanceof BroadcastFilter
+ ? BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__RUNTIME
+ : BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST,
+ r.mIsReceiverAppRunning
+ ? BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM
+ : BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD,
+ r.dispatchTime - r.enqueueTime,
+ r.receiverTime - r.dispatchTime,
+ finishTime - r.receiverTime);
+ }
if (state == BroadcastRecord.IDLE) {
Slog.w(TAG_BROADCAST, "finishReceiver [" + mQueueName + "] called but state is IDLE");
}
@@ -640,7 +653,8 @@
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser,
- int receiverUid, int callingUid) throws RemoteException {
+ int receiverUid, int callingUid, long dispatchDelay,
+ long receiveDelay) throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
if (app != null) {
final IApplicationThread thread = app.getThread();
@@ -674,12 +688,15 @@
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
- FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED,
- receiverUid == -1 ? Process.SYSTEM_UID : receiverUid,
- callingUid == -1 ? Process.SYSTEM_UID : callingUid,
- ActivityManagerService.getShortAction(intent.getAction()),
- BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__RUNTIME,
- BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM);
+ if (!ordered) {
+ FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED,
+ receiverUid == -1 ? Process.SYSTEM_UID : receiverUid,
+ callingUid == -1 ? Process.SYSTEM_UID : callingUid,
+ ActivityManagerService.getShortAction(intent.getAction()),
+ BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__RUNTIME,
+ BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM,
+ dispatchDelay, receiveDelay, 0 /* finish_delay */);
+ }
}
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
@@ -960,10 +977,11 @@
filter.receiverList.app.mReceivers.addCurReceiver(r);
mService.enqueueOomAdjTargetLocked(r.curApp);
mService.updateOomAdjPendingTargetsLocked(
- OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
+ OOM_ADJ_REASON_START_RECEIVER);
}
} else if (filter.receiverList.app != null) {
- mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(filter.receiverList.app);
+ mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(filter.receiverList.app,
+ OOM_ADJ_REASON_START_RECEIVER);
}
try {
@@ -983,7 +1001,9 @@
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId,
- filter.receiverList.uid, r.callingUid);
+ filter.receiverList.uid, r.callingUid,
+ r.dispatchTime - r.enqueueTime,
+ r.receiverTime - r.dispatchTime);
// parallel broadcasts are fire-and-forget, not bookended by a call to
// finishReceiverLocked(), so we manage their activity-start token here
if (filter.receiverList.app != null
@@ -1166,6 +1186,7 @@
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchRealTime = SystemClock.elapsedRealtime();
r.dispatchClockTime = System.currentTimeMillis();
+ r.mIsReceiverAppRunning = true;
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
@@ -1244,7 +1265,7 @@
// make sure all processes have correct oom and sched
// adjustments.
mService.updateOomAdjPendingTargetsLocked(
- OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
+ OOM_ADJ_REASON_START_RECEIVER);
}
// when we have no more ordered broadcast on this queue, stop logging
@@ -1326,17 +1347,25 @@
if (sendResult) {
if (r.callerApp != null) {
mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(
- r.callerApp);
+ r.callerApp, OOM_ADJ_REASON_FINISH_RECEIVER);
}
try {
if (DEBUG_BROADCAST) {
Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] "
+ r.intent.getAction() + " app=" + r.callerApp);
}
+ if (r.dispatchTime == 0) {
+ // The dispatch time here could be 0, in case it's a parallel
+ // broadcast but it has a result receiver. Set it to now.
+ r.dispatchTime = now;
+ }
+ r.mIsReceiverAppRunning = true;
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId,
- r.callingUid, r.callingUid);
+ r.callingUid, r.callingUid,
+ r.dispatchTime - r.enqueueTime,
+ now - r.dispatchTime);
logBootCompletedBroadcastCompletionLatencyIfPossible(r);
// Set this to null so that the reference
// (local and remote) isn't kept in the mBroadcastHistory.
@@ -1493,6 +1522,7 @@
"Delivering ordered ["
+ mQueueName + "] to registered "
+ filter + ": " + r);
+ r.mIsReceiverAppRunning = true;
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
if (r.receiver == null || !r.ordered) {
// The receiver has already finished, so schedule to
@@ -1856,9 +1886,8 @@
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
maybeAddAllowBackgroundActivityStartsToken(app, r);
- processCurBroadcastLocked(r, app,
- BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST,
- BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM);
+ r.mIsReceiverAppRunning = true;
+ processCurBroadcastLocked(r, app);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when sending broadcast to "
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index ae91d75..ce4528b 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -135,6 +135,8 @@
ComponentName curComponent; // the receiver class that is currently running.
ActivityInfo curReceiver; // info about the receiver that is currently running.
+ boolean mIsReceiverAppRunning; // Was the receiver's app already running.
+
// Private refcount-management bookkeeping; start > 0
static AtomicInteger sNextToken = new AtomicInteger(1);
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index c88d82c..0d3685d 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -38,6 +38,7 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.EventLog;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -719,7 +720,7 @@
}
if (!enable && opt.isFrozen()) {
- unfreezeAppLSP(process);
+ unfreezeAppLSP(process, OomAdjuster.OOM_ADJ_REASON_NONE);
// Set freezerOverride *after* calling unfreezeAppLSP (it resets the flag)
opt.setFreezerOverride(true);
@@ -1030,11 +1031,11 @@
// This will ensure app will be out of the freezer for at least mFreezerDebounceTimeout.
@GuardedBy("mAm")
- void unfreezeTemporarily(ProcessRecord app) {
+ void unfreezeTemporarily(ProcessRecord app, String reason) {
if (mUseFreezer) {
synchronized (mProcLock) {
if (app.mOptRecord.isFrozen() || app.mOptRecord.isPendingFreeze()) {
- unfreezeAppLSP(app);
+ unfreezeAppLSP(app, reason);
freezeAppAsyncLSP(app);
}
}
@@ -1060,7 +1061,7 @@
}
@GuardedBy({"mAm", "mProcLock", "mFreezerLock"})
- void unfreezeAppInternalLSP(ProcessRecord app) {
+ void unfreezeAppInternalLSP(ProcessRecord app, String reason) {
final int pid = app.getPid();
final ProcessCachedOptimizerRecord opt = app.mOptRecord;
if (opt.isPendingFreeze()) {
@@ -1141,14 +1142,14 @@
mFreezeHandler.obtainMessage(REPORT_UNFREEZE_MSG,
pid,
(int) Math.min(opt.getFreezeUnfreezeTime() - freezeTime, Integer.MAX_VALUE),
- app.processName));
+ new Pair<String, String>(app.processName, reason)));
}
}
@GuardedBy({"mAm", "mProcLock"})
- void unfreezeAppLSP(ProcessRecord app) {
+ void unfreezeAppLSP(ProcessRecord app, String reason) {
synchronized (mFreezerLock) {
- unfreezeAppInternalLSP(app);
+ unfreezeAppInternalLSP(app, reason);
}
}
@@ -1159,25 +1160,14 @@
* The caller of this function should still trigger updateOomAdj for AMS to unfreeze the app.
* @param pid pid of the process to be unfrozen
*/
- void unfreezeProcess(int pid) {
+ void unfreezeProcess(int pid, String reason) {
synchronized (mFreezerLock) {
ProcessRecord app = mFrozenProcesses.get(pid);
if (app == null) {
return;
}
Slog.d(TAG_AM, "quick sync unfreeze " + pid);
- try {
- freezeBinder(pid, false);
- } catch (RuntimeException e) {
- Slog.e(TAG_AM, "Unable to quick unfreeze binder for " + pid);
- return;
- }
-
- try {
- Process.setProcessFrozen(pid, app.uid, false);
- } catch (Exception e) {
- Slog.e(TAG_AM, "Unable to quick unfreeze " + pid);
- }
+ unfreezeAppLSP(app, reason);
}
}
@@ -1628,9 +1618,11 @@
case REPORT_UNFREEZE_MSG:
int pid = msg.arg1;
int frozenDuration = msg.arg2;
- String processName = (String) msg.obj;
+ Pair<String, String> obj = (Pair<String, String>) msg.obj;
+ String processName = obj.first;
+ String reason = obj.second;
- reportUnfreeze(pid, frozenDuration, processName);
+ reportUnfreeze(pid, frozenDuration, processName, reason);
break;
default:
return;
@@ -1641,7 +1633,7 @@
private void rescheduleFreeze(final ProcessRecord proc, final String reason) {
Slog.d(TAG_AM, "Reschedule freeze for process " + proc.getPid()
+ " " + proc.processName + " (" + reason + ")");
- unfreezeAppLSP(proc);
+ unfreezeAppLSP(proc, OomAdjuster.OOM_ADJ_REASON_NONE);
freezeAppAsyncLSP(proc);
}
@@ -1729,7 +1721,8 @@
FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__FREEZE_APP,
pid,
name,
- unfrozenDuration);
+ unfrozenDuration,
+ FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__NONE);
}
try {
@@ -1759,12 +1752,13 @@
} catch (Exception e) {
Slog.e(TAG_AM, "Unable to check file locks for " + name + "(" + pid + "): " + e);
synchronized (mProcLock) {
- unfreezeAppLSP(proc);
+ unfreezeAppLSP(proc, OomAdjuster.OOM_ADJ_REASON_NONE);
}
}
}
- private void reportUnfreeze(int pid, int frozenDuration, String processName) {
+ private void reportUnfreeze(int pid, int frozenDuration, String processName,
+ String reason) {
EventLog.writeEvent(EventLogTags.AM_UNFREEZE, pid, processName);
@@ -1775,7 +1769,39 @@
FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__UNFREEZE_APP,
pid,
processName,
- frozenDuration);
+ frozenDuration,
+ getUnfreezeReasonCode(reason));
+ }
+ }
+
+ private int getUnfreezeReasonCode(String oomAdjReason) {
+ switch (oomAdjReason) {
+ case OomAdjuster.OOM_ADJ_REASON_ACTIVITY:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__ACTIVITY;
+ case OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__FINISH_RECEIVER;
+ case OomAdjuster.OOM_ADJ_REASON_START_RECEIVER:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__START_RECEIVER;
+ case OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__BIND_SERVICE;
+ case OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__UNBIND_SERVICE;
+ case OomAdjuster.OOM_ADJ_REASON_START_SERVICE:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__START_SERVICE;
+ case OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__GET_PROVIDER;
+ case OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__REMOVE_PROVIDER;
+ case OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__UI_VISIBILITY;
+ case OomAdjuster.OOM_ADJ_REASON_ALLOWLIST:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__ALLOWLIST;
+ case OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__PROCESS_BEGIN;
+ case OomAdjuster.OOM_ADJ_REASON_PROCESS_END:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__PROCESS_END;
+ default:
+ return FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__NONE;
}
}
@@ -1789,7 +1815,7 @@
ProcessRecord app = mFrozenProcesses.get(pid);
if (app != null) {
Slog.i(TAG_AM, app.processName + " (" + pid + ") holds blocking file lock");
- unfreezeAppLSP(app);
+ unfreezeAppLSP(app, OomAdjuster.OOM_ADJ_REASON_NONE);
}
}
}
diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java
index 9158891..4380b42 100644
--- a/services/core/java/com/android/server/am/LmkdStatsReporter.java
+++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java
@@ -50,7 +50,8 @@
* Logs the event when LMKD kills a process to reduce memory pressure.
* Code: LMK_KILL_OCCURRED = 51
*/
- public static void logKillOccurred(DataInputStream inputData) {
+ public static void logKillOccurred(DataInputStream inputData, int totalForegroundServices,
+ int procsWithForegroundServices) {
try {
final long pgFault = inputData.readLong();
final long pgMajFault = inputData.readLong();
@@ -67,11 +68,10 @@
final int thrashing = inputData.readInt();
final int maxThrashing = inputData.readInt();
final String procName = inputData.readUTF();
-
FrameworkStatsLog.write(FrameworkStatsLog.LMK_KILL_OCCURRED, uid, procName, oomScore,
pgFault, pgMajFault, rssInBytes, cacheInBytes, swapInBytes, processStartTimeNS,
minOomScore, freeMemKb, freeSwapKb, mapKillReason(killReason), thrashing,
- maxThrashing);
+ maxThrashing, totalForegroundServices, procsWithForegroundServices);
} catch (IOException e) {
Slog.e(TAG, "Invalid buffer data. Failed to log LMK_KILL_OCCURRED");
return;
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index e9658db..bc939d6 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -367,7 +367,7 @@
*/
@GuardedBy({"mService", "mProcLock"})
private boolean performUpdateOomAdjLSP(ProcessRecord app, int cachedAdj,
- ProcessRecord topApp, long now) {
+ ProcessRecord topApp, long now, String oomAdjReason) {
if (app.getThread() == null) {
return false;
}
@@ -411,7 +411,7 @@
}
}
- return applyOomAdjLSP(app, false, now, SystemClock.elapsedRealtime());
+ return applyOomAdjLSP(app, false, now, SystemClock.elapsedRealtime(), oomAdjReason);
}
/**
@@ -510,7 +510,7 @@
// Check if this process is in the pending list too, remove from pending list if so.
mPendingProcessSet.remove(app);
boolean success = performUpdateOomAdjLSP(app, cachedAdj, topApp,
- SystemClock.uptimeMillis());
+ SystemClock.uptimeMillis(), oomAdjReason);
// The 'app' here itself might or might not be in the cycle, for example,
// the case A <=> B vs. A -> B <=> C; anyway, if we spot a cycle here, re-compute them.
if (!success || (wasCached == state.isCached() && oldAdj != ProcessList.INVALID_ADJ
@@ -563,7 +563,7 @@
processes.add(app);
assignCachedAdjIfNecessary(processes);
applyOomAdjLSP(app, false, SystemClock.uptimeMillis(),
- SystemClock.elapsedRealtime());
+ SystemClock.elapsedRealtime(), oomAdjReason);
}
mTmpProcessList.clear();
mService.mOomAdjProfiler.oomAdjEnded();
@@ -857,7 +857,8 @@
mNumNonCachedProcs = 0;
mNumCachedHiddenProcs = 0;
- boolean allChanged = updateAndTrimProcessLSP(now, nowElapsed, oldTime, activeUids);
+ boolean allChanged = updateAndTrimProcessLSP(now, nowElapsed, oldTime, activeUids,
+ oomAdjReason);
mNumServiceProcs = mNewNumServiceProcs;
if (mService.mAlwaysFinishActivities) {
@@ -1035,7 +1036,7 @@
@GuardedBy({"mService", "mProcLock"})
private boolean updateAndTrimProcessLSP(final long now, final long nowElapsed,
- final long oldTime, final ActiveUids activeUids) {
+ final long oldTime, final ActiveUids activeUids, String oomAdjReason) {
ArrayList<ProcessRecord> lruList = mProcessList.getLruProcessesLOSP();
final int numLru = lruList.size();
@@ -1063,7 +1064,7 @@
if (!app.isKilledByAm() && app.getThread() != null) {
// We don't need to apply the update for the process which didn't get computed
if (state.getCompletedAdjSeq() == mAdjSeq) {
- applyOomAdjLSP(app, true, now, nowElapsed);
+ applyOomAdjLSP(app, true, now, nowElapsed, oomAdjReason);
}
final ProcessServiceRecord psr = app.mServices;
@@ -2556,7 +2557,7 @@
/** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
@GuardedBy({"mService", "mProcLock"})
private boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
- long nowElapsed) {
+ long nowElapsed, String oomAdjReson) {
boolean success = true;
final ProcessStateRecord state = app.mState;
final UidRecord uidRec = app.getUidRecord();
@@ -2713,7 +2714,7 @@
changes |= ActivityManagerService.ProcessChangeItem.CHANGE_ACTIVITIES;
}
- updateAppFreezeStateLSP(app);
+ updateAppFreezeStateLSP(app, oomAdjReson);
if (state.getReportedProcState() != state.getCurProcState()) {
state.setReportedProcState(state.getCurProcState());
@@ -3074,7 +3075,7 @@
}
@GuardedBy({"mService", "mProcLock"})
- private void updateAppFreezeStateLSP(ProcessRecord app) {
+ private void updateAppFreezeStateLSP(ProcessRecord app, String oomAdjReason) {
if (!mCachedAppOptimizer.useFreezer()) {
return;
}
@@ -3086,7 +3087,7 @@
final ProcessCachedOptimizerRecord opt = app.mOptRecord;
// if an app is already frozen and shouldNotFreeze becomes true, immediately unfreeze
if (opt.isFrozen() && opt.shouldNotFreeze()) {
- mCachedAppOptimizer.unfreezeAppLSP(app);
+ mCachedAppOptimizer.unfreezeAppLSP(app, oomAdjReason);
return;
}
@@ -3096,7 +3097,7 @@
&& !opt.shouldNotFreeze()) {
mCachedAppOptimizer.freezeAppAsyncLSP(app);
} else if (state.getSetAdj() < ProcessList.CACHED_APP_MIN_ADJ) {
- mCachedAppOptimizer.unfreezeAppLSP(app);
+ mCachedAppOptimizer.unfreezeAppLSP(app, oomAdjReason);
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 98e3a21..a8d7e13 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -814,7 +814,12 @@
< LmkdStatsReporter.KILL_OCCURRED_MSG_SIZE) {
return false;
}
- LmkdStatsReporter.logKillOccurred(inputData);
+ Pair<Integer, Integer> temp = getNumForegroundServices();
+ final int totalForegroundServices = temp.first;
+ final int procsWithForegroundServices = temp.second;
+ LmkdStatsReporter.logKillOccurred(inputData,
+ totalForegroundServices,
+ procsWithForegroundServices);
return true;
case LMK_STATE_CHANGED:
if (receivedLen
@@ -5123,6 +5128,26 @@
}
}
+ /**
+ * Get the number of foreground services in all processes and number of processes that have
+ * foreground service within.
+ */
+ Pair<Integer, Integer> getNumForegroundServices() {
+ int numForegroundServices = 0;
+ int procs = 0;
+ synchronized (mService) {
+ for (int i = 0, size = mLruProcesses.size(); i < size; i++) {
+ ProcessRecord pr = mLruProcesses.get(i);
+ int numFgs = pr.mServices.getNumForegroundServices();
+ if (numFgs > 0) {
+ numForegroundServices += numFgs;
+ procs++;
+ }
+ }
+ }
+ return new Pair<>(numForegroundServices, procs);
+ }
+
private final class ImperceptibleKillRunner extends IUidObserver.Stub {
private static final String EXTRA_PID = "pid";
private static final String EXTRA_UID = "uid";
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 9951e98..67eb675 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -180,6 +180,16 @@
mRepFgServiceTypes = foregroundServiceTypes;
}
+ int getNumForegroundServices() {
+ int count = 0;
+ for (int i = 0, serviceCount = mServices.size(); i < serviceCount; i++) {
+ if (mServices.valueAt(i).isForeground) {
+ count++;
+ }
+ }
+ return count;
+ }
+
void updateHasTopStartedAlmostPerceptibleServices() {
mHasTopStartedAlmostPerceptibleServices = false;
mLastTopStartedAlmostPerceptibleBindRequestUptimeMs = 0;
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 262436d..eb1fd3a 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -497,6 +497,7 @@
@GuardedBy({"mService", "mProcLock"})
void setCurAdj(int curAdj) {
mCurAdj = curAdj;
+ mApp.getWindowProcessController().setCurrentAdj(curAdj);
}
@GuardedBy(anyOf = {"mService", "mProcLock"})
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index d16fe12..d4ef638 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -343,6 +343,9 @@
*
* Calling this multiple times for duplicate requests will be no-ops, returning true.
*
+ * TODO(b/239130847): Maintain the proximity state in AttentionManagerService and change this
+ * to a polling API.
+ *
* @return {@code true} if the framework was able to dispatch the request
*/
@VisibleForTesting
@@ -853,9 +856,6 @@
@GuardedBy("mLock")
private void cancelAndUnbindLocked() {
synchronized (mLock) {
- if (mCurrentAttentionCheck == null && mCurrentProximityUpdate == null) {
- return;
- }
if (mCurrentAttentionCheck != null) {
cancel();
}
@@ -937,7 +937,7 @@
}
}
- class TestableProximityUpdateCallbackInternal extends ProximityUpdateCallbackInternal {
+ class TestableProximityUpdateCallbackInternal implements ProximityUpdateCallbackInternal {
private double mLastCallbackCode = PROXIMITY_UNKNOWN;
@Override
@@ -1069,6 +1069,7 @@
private void resetStates() {
synchronized (mLock) {
mCurrentProximityUpdate = null;
+ cancelAndUnbindLocked();
}
mComponentName = resolveAttentionService(mContext);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c00c298..0a081bf 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1614,6 +1614,7 @@
}
synchronized (mAudioPolicies) {
+ ArrayList<AudioPolicyProxy> invalidProxies = new ArrayList<>();
for (AudioPolicyProxy policy : mAudioPolicies.values()) {
final int status = policy.connectMixes();
if (status != AudioSystem.SUCCESS) {
@@ -1621,7 +1622,7 @@
Log.e(TAG, "onAudioServerDied: error "
+ AudioSystem.audioSystemErrorToString(status)
+ " when connecting mixes for policy " + policy.toLogFriendlyString());
- policy.release();
+ invalidProxies.add(policy);
} else {
final int deviceAffinitiesStatus = policy.setupDeviceAffinities();
if (deviceAffinitiesStatus != AudioSystem.SUCCESS) {
@@ -1629,10 +1630,12 @@
+ AudioSystem.audioSystemErrorToString(deviceAffinitiesStatus)
+ " when connecting device affinities for policy "
+ policy.toLogFriendlyString());
- policy.release();
+ invalidProxies.add(policy);
}
}
}
+ invalidProxies.forEach((policy) -> policy.release());
+
}
// Restore capture policies
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 8356134..5eaa948 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -727,8 +727,11 @@
}
private boolean isDeviceCompatibleWithSpatializationModes(@NonNull AudioDeviceAttributes ada) {
+ // modeForDevice will be neither transaural or binaural for devices that do not support
+ // spatial audio. For instance mono devices like earpiece, speaker safe or sco must
+ // not be included.
final byte modeForDevice = (byte) SPAT_MODE_FOR_DEVICE_TYPE.get(ada.getType(),
- /*default when type not found*/ SpatializationMode.SPATIALIZER_BINAURAL);
+ /*default when type not found*/ -1);
if ((modeForDevice == SpatializationMode.SPATIALIZER_BINAURAL && mBinauralSupported)
|| (modeForDevice == SpatializationMode.SPATIALIZER_TRANSAURAL
&& mTransauralSupported)) {
@@ -1536,8 +1539,8 @@
@Override
public String toString() {
- return "type:" + mDeviceType + " addr:" + mDeviceAddress + " enabled:" + mEnabled
- + " HT:" + mHasHeadTracker + " HTenabled:" + mHeadTrackerEnabled;
+ return "type: " + mDeviceType + " addr: " + mDeviceAddress + " enabled: " + mEnabled
+ + " HT: " + mHasHeadTracker + " HTenabled: " + mHeadTrackerEnabled;
}
String toPersistableString() {
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index 9a19031..6759d79 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -32,6 +32,7 @@
import android.os.PowerWhitelistManager;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.EventLog;
import android.util.Log;
import android.view.KeyEvent;
@@ -117,6 +118,12 @@
int componentType = getComponentType(pendingIntent);
ComponentName componentName = getComponentName(pendingIntent, componentType);
if (componentName != null) {
+ if (!TextUtils.equals(componentName.getPackageName(), sessionPackageName)) {
+ EventLog.writeEvent(0x534e4554, "238177121", -1, ""); // SafetyNet logging
+ throw new IllegalArgumentException("ComponentName does not belong to "
+ + "sessionPackageName. sessionPackageName = " + sessionPackageName
+ + ", ComponentName pkg = " + componentName.getPackageName());
+ }
return new MediaButtonReceiverHolder(userId, pendingIntent, componentName,
componentType);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 604e8f3..b8131a8 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -52,6 +52,8 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.EventLog;
import android.util.Log;
import android.view.KeyEvent;
@@ -938,6 +940,14 @@
@Override
public void setMediaButtonReceiver(PendingIntent pi, String sessionPackageName)
throws RemoteException {
+ //mPackageName has been verified in MediaSessionService.enforcePackageName().
+ if (!TextUtils.equals(sessionPackageName, mPackageName)) {
+ EventLog.writeEvent(0x534e4554, "238177121", -1, ""); // SafetyNet logging
+ throw new IllegalArgumentException("sessionPackageName name does not match "
+ + "package name provided to MediaSessionRecord. sessionPackageName = "
+ + sessionPackageName + ", pkg = "
+ + mPackageName);
+ }
final long token = Binder.clearCallingIdentity();
try {
if ((mPolicies & MediaSessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER)
@@ -956,6 +966,15 @@
public void setMediaButtonBroadcastReceiver(ComponentName receiver) throws RemoteException {
final long token = Binder.clearCallingIdentity();
try {
+ //mPackageName has been verified in MediaSessionService.enforcePackageName().
+ if (receiver != null && !TextUtils.equals(
+ mPackageName, receiver.getPackageName())) {
+ EventLog.writeEvent(0x534e4554, "238177121", -1, ""); // SafetyNet logging
+ throw new IllegalArgumentException("receiver does not belong to "
+ + "package name provided to MediaSessionRecord. Pkg = " + mPackageName
+ + ", Receiver Pkg = " + receiver.getPackageName());
+ }
+
if ((mPolicies & MediaSessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER)
!= 0) {
return;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7771a40..2f34ccd 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1444,6 +1444,11 @@
}
if (flags != data.getFlags()) {
+ int changedFlags = data.getFlags() ^ flags;
+ if ((changedFlags & FLAG_SUPPRESS_NOTIFICATION) != 0) {
+ // Suppress notification flag changed, clear any effects
+ clearEffectsLocked(key);
+ }
data.setFlags(flags);
// Shouldn't alert again just because of a flag change.
r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
@@ -1595,6 +1600,20 @@
updateLightsLocked();
}
+ @GuardedBy("mNotificationLock")
+ private void clearEffectsLocked(String key) {
+ if (key.equals(mSoundNotificationKey)) {
+ clearSoundLocked();
+ }
+ if (key.equals(mVibrateNotificationKey)) {
+ clearVibrateLocked();
+ }
+ boolean removed = mLights.remove(key);
+ if (removed) {
+ updateLightsLocked();
+ }
+ }
+
protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -6666,6 +6685,20 @@
}
}
+ // Ensure only allowed packages have a substitute app name
+ if (notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) {
+ int hasSubstituteAppNamePermission = mPackageManager.checkPermission(
+ permission.SUBSTITUTE_NOTIFICATION_APP_NAME, pkg, userId);
+ if (hasSubstituteAppNamePermission != PERMISSION_GRANTED) {
+ notification.extras.remove(Notification.EXTRA_SUBSTITUTE_APP_NAME);
+ if (DBG) {
+ Slog.w(TAG, "warning: pkg " + pkg + " attempting to substitute app name"
+ + " without holding perm "
+ + Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME);
+ }
+ }
+ }
+
// Remote views? Are they too big?
checkRemoteViews(pkg, tag, id, notification);
}
@@ -7815,7 +7848,8 @@
&& (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_STATUS_BAR) != 0;
if (!record.isUpdate
&& record.getImportance() > IMPORTANCE_MIN
- && !suppressedByDnd) {
+ && !suppressedByDnd
+ && isNotificationForCurrentUser(record)) {
sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 477b8da..729c521 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -86,6 +86,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -1327,16 +1328,17 @@
return null;
}
NotificationChannelGroup group = r.groups.get(groupId).clone();
- group.setChannels(new ArrayList<>());
+ ArrayList channels = new ArrayList();
int N = r.channels.size();
for (int i = 0; i < N; i++) {
final NotificationChannel nc = r.channels.valueAt(i);
if (includeDeleted || !nc.isDeleted()) {
if (groupId.equals(nc.getGroup())) {
- group.addChannel(nc);
+ channels.add(nc);
}
}
}
+ group.setChannels(channels);
return group;
}
}
@@ -1349,7 +1351,10 @@
if (r == null) {
return null;
}
- return r.groups.get(groupId);
+ if (r.groups.get(groupId) != null) {
+ return r.groups.get(groupId).clone();
+ }
+ return null;
}
}
@@ -1357,44 +1362,48 @@
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty) {
Objects.requireNonNull(pkg);
- Map<String, NotificationChannelGroup> groups = new ArrayMap<>();
+ List<NotificationChannelGroup> groups = new ArrayList<>();
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
if (r == null) {
return ParceledListSlice.emptyList();
}
- NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null);
+ Map<String, ArrayList<NotificationChannel>> groupedChannels = new HashMap();
int N = r.channels.size();
for (int i = 0; i < N; i++) {
final NotificationChannel nc = r.channels.valueAt(i);
if (includeDeleted || !nc.isDeleted()) {
if (nc.getGroup() != null) {
if (r.groups.get(nc.getGroup()) != null) {
- NotificationChannelGroup ncg = groups.get(nc.getGroup());
- if (ncg == null) {
- ncg = r.groups.get(nc.getGroup()).clone();
- ncg.setChannels(new ArrayList<>());
- groups.put(nc.getGroup(), ncg);
-
- }
- ncg.addChannel(nc);
+ ArrayList<NotificationChannel> channels = groupedChannels.getOrDefault(
+ nc.getGroup(), new ArrayList<>());
+ channels.add(nc);
+ groupedChannels.put(nc.getGroup(), channels);
}
} else {
- nonGrouped.addChannel(nc);
+ ArrayList<NotificationChannel> channels = groupedChannels.getOrDefault(
+ null, new ArrayList<>());
+ channels.add(nc);
+ groupedChannels.put(null, channels);
}
}
}
- if (includeNonGrouped && nonGrouped.getChannels().size() > 0) {
- groups.put(null, nonGrouped);
- }
- if (includeEmpty) {
- for (NotificationChannelGroup group : r.groups.values()) {
- if (!groups.containsKey(group.getId())) {
- groups.put(group.getId(), group);
- }
+ for (NotificationChannelGroup group : r.groups.values()) {
+ ArrayList<NotificationChannel> channels =
+ groupedChannels.getOrDefault(group.getId(), new ArrayList<>());
+ if (includeEmpty || !channels.isEmpty()) {
+ NotificationChannelGroup clone = group.clone();
+ clone.setChannels(channels);
+ groups.add(clone);
}
}
- return new ParceledListSlice<>(new ArrayList<>(groups.values()));
+
+ if (includeNonGrouped && groupedChannels.containsKey(null)) {
+ NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null);
+ nonGrouped.setChannels(groupedChannels.get(null));
+ groups.add(nonGrouped);
+ }
+ return new ParceledListSlice<>(groups);
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d645bb2..8731ac0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5107,18 +5107,10 @@
/** {@inheritDoc} */
@Override
- public void userActivity() {
- // ***************************************
- // NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
- // ***************************************
- // THIS IS CALLED FROM DEEP IN THE POWER MANAGER
- // WITH ITS LOCKS HELD.
- //
- // This code must be VERY careful about the locks
- // it acquires.
- // In fact, the current code acquires way too many,
- // and probably has lurking deadlocks.
-
+ public void userActivity(int displayGroupId, int event) {
+ if (displayGroupId == DEFAULT_DISPLAY && event == PowerManager.USER_ACTIVITY_EVENT_TOUCH) {
+ mDefaultDisplayPolicy.onUserActivityEventTouch();
+ }
synchronized (mScreenLockTimeout) {
if (mLockScreenTimerActive) {
// reset the timer
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index e8a3dcd..4f00992 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1006,7 +1006,7 @@
* Called when userActivity is signalled in the power manager.
* This is safe to call from any thread, with any window manager locks held or not.
*/
- public void userActivity();
+ void userActivity(int displayGroupId, int event);
/**
* Called when we have finished booting and can now display the home
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 685b744..dad9584 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -571,7 +571,8 @@
/**
* Called when there has been user activity.
*/
- public void onUserActivity(int displayGroupId, int event, int uid) {
+ public void onUserActivity(int displayGroupId, @PowerManager.UserActivityEvent int event,
+ int uid) {
if (DEBUG) {
Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
}
@@ -712,7 +713,7 @@
}
TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
tm.notifyUserActivity();
- mPolicy.userActivity();
+ mPolicy.userActivity(displayGroupId, event);
mFaceDownDetector.userActivity(event);
mScreenUndimDetector.userActivity(displayGroupId);
}
diff --git a/services/core/java/com/android/server/power/PowerGroup.java b/services/core/java/com/android/server/power/PowerGroup.java
index fec61ac..9fe53fb 100644
--- a/services/core/java/com/android/server/power/PowerGroup.java
+++ b/services/core/java/com/android/server/power/PowerGroup.java
@@ -74,6 +74,8 @@
private long mLastPowerOnTime;
private long mLastUserActivityTime;
private long mLastUserActivityTimeNoChangeLights;
+ @PowerManager.UserActivityEvent
+ private int mLastUserActivityEvent;
/** Timestamp (milliseconds since boot) of the last time the power group was awoken.*/
private long mLastWakeTime;
/** Timestamp (milliseconds since boot) of the last time the power group was put to sleep. */
@@ -244,7 +246,7 @@
return true;
}
- boolean dozeLocked(long eventTime, int uid, int reason) {
+ boolean dozeLocked(long eventTime, int uid, @PowerManager.GoToSleepReason int reason) {
if (eventTime < getLastWakeTimeLocked() || !isInteractive(mWakefulness)) {
return false;
}
@@ -253,9 +255,14 @@
try {
reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
+ long millisSinceLastUserActivity = eventTime - Math.max(
+ mLastUserActivityTimeNoChangeLights, mLastUserActivityTime);
Slog.i(TAG, "Powering off display group due to "
- + PowerManager.sleepReasonToString(reason) + " (groupId= " + getGroupId()
- + ", uid= " + uid + ")...");
+ + PowerManager.sleepReasonToString(reason)
+ + " (groupId= " + getGroupId() + ", uid= " + uid
+ + ", millisSinceLastUserActivity=" + millisSinceLastUserActivity
+ + ", lastUserActivityEvent=" + PowerManager.userActivityEventToString(
+ mLastUserActivityEvent) + ")...");
setSandmanSummonedLocked(/* isSandmanSummoned= */ true);
setWakefulnessLocked(WAKEFULNESS_DOZING, eventTime, uid, reason, /* opUid= */ 0,
@@ -266,14 +273,16 @@
return true;
}
- boolean sleepLocked(long eventTime, int uid, int reason) {
+ boolean sleepLocked(long eventTime, int uid, @PowerManager.GoToSleepReason int reason) {
if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "sleepPowerGroup");
try {
- Slog.i(TAG, "Sleeping power group (groupId=" + getGroupId() + ", uid=" + uid + ")...");
+ Slog.i(TAG,
+ "Sleeping power group (groupId=" + getGroupId() + ", uid=" + uid + ", reason="
+ + PowerManager.sleepReasonToString(reason) + ")...");
setSandmanSummonedLocked(/* isSandmanSummoned= */ true);
setWakefulnessLocked(WAKEFULNESS_ASLEEP, eventTime, uid, reason, /* opUid= */0,
/* opPackageName= */ null, /* details= */ null);
@@ -287,16 +296,20 @@
return mLastUserActivityTime;
}
- void setLastUserActivityTimeLocked(long lastUserActivityTime) {
+ void setLastUserActivityTimeLocked(long lastUserActivityTime,
+ @PowerManager.UserActivityEvent int event) {
mLastUserActivityTime = lastUserActivityTime;
+ mLastUserActivityEvent = event;
}
public long getLastUserActivityTimeNoChangeLightsLocked() {
return mLastUserActivityTimeNoChangeLights;
}
- public void setLastUserActivityTimeNoChangeLightsLocked(long time) {
+ public void setLastUserActivityTimeNoChangeLightsLocked(long time,
+ @PowerManager.UserActivityEvent int event) {
mLastUserActivityTimeNoChangeLights = time;
+ mLastUserActivityEvent = event;
}
public int getUserActivitySummaryLocked() {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index dbf05f1..bc93cb3 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1169,6 +1169,7 @@
return;
}
+ Slog.i(TAG, "onFlip(): Face " + (isFaceDown ? "down." : "up."));
mIsFaceDown = isFaceDown;
if (isFaceDown) {
final long currentTime = mClock.uptimeMillis();
@@ -1888,12 +1889,13 @@
// Called from native code.
@SuppressWarnings("unused")
- private void userActivityFromNative(long eventTime, int event, int displayId, int flags) {
+ private void userActivityFromNative(long eventTime, @PowerManager.UserActivityEvent int event,
+ int displayId, int flags) {
userActivityInternal(displayId, eventTime, event, flags, Process.SYSTEM_UID);
}
- private void userActivityInternal(int displayId, long eventTime, int event, int flags,
- int uid) {
+ private void userActivityInternal(int displayId, long eventTime,
+ @PowerManager.UserActivityEvent int event, int flags, int uid) {
synchronized (mLock) {
if (displayId == Display.INVALID_DISPLAY) {
if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {
@@ -1944,11 +1946,12 @@
@GuardedBy("mLock")
private boolean userActivityNoUpdateLocked(final PowerGroup powerGroup, long eventTime,
- int event, int flags, int uid) {
+ @PowerManager.UserActivityEvent int event, int flags, int uid) {
final int groupId = powerGroup.getGroupId();
if (DEBUG_SPEW) {
Slog.d(TAG, "userActivityNoUpdateLocked: groupId=" + groupId
- + ", eventTime=" + eventTime + ", event=" + event
+ + ", eventTime=" + eventTime
+ + ", event=" + PowerManager.userActivityEventToString(event)
+ ", flags=0x" + Integer.toHexString(flags) + ", uid=" + uid);
}
@@ -1983,7 +1986,7 @@
if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
if (eventTime > powerGroup.getLastUserActivityTimeNoChangeLightsLocked()
&& eventTime > powerGroup.getLastUserActivityTimeLocked()) {
- powerGroup.setLastUserActivityTimeNoChangeLightsLocked(eventTime);
+ powerGroup.setLastUserActivityTimeNoChangeLightsLocked(eventTime, event);
mDirty |= DIRTY_USER_ACTIVITY;
if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
mDirty |= DIRTY_QUIESCENT;
@@ -1993,7 +1996,7 @@
}
} else {
if (eventTime > powerGroup.getLastUserActivityTimeLocked()) {
- powerGroup.setLastUserActivityTimeLocked(eventTime);
+ powerGroup.setLastUserActivityTimeLocked(eventTime, event);
mDirty |= DIRTY_USER_ACTIVITY;
if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
mDirty |= DIRTY_QUIESCENT;
@@ -2020,7 +2023,8 @@
@WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "wakePowerGroupLocked: eventTime=" + eventTime
- + ", groupId=" + powerGroup.getGroupId() + ", uid=" + uid);
+ + ", groupId=" + powerGroup.getGroupId()
+ + ", reason=" + PowerManager.wakeReasonToString(reason) + ", uid=" + uid);
}
if (mForceSuspendActive || !mSystemReady) {
return;
@@ -2043,11 +2047,11 @@
@GuardedBy("mLock")
private boolean dozePowerGroupLocked(final PowerGroup powerGroup, long eventTime,
- int reason, int uid) {
+ @GoToSleepReason int reason, int uid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "dozePowerGroup: eventTime=" + eventTime
- + ", groupId=" + powerGroup.getGroupId() + ", reason=" + reason
- + ", uid=" + uid);
+ + ", groupId=" + powerGroup.getGroupId()
+ + ", reason=" + PowerManager.sleepReasonToString(reason) + ", uid=" + uid);
}
if (!mSystemReady || !mBootCompleted) {
@@ -2058,10 +2062,12 @@
}
@GuardedBy("mLock")
- private boolean sleepPowerGroupLocked(final PowerGroup powerGroup, long eventTime, int reason,
- int uid) {
+ private boolean sleepPowerGroupLocked(final PowerGroup powerGroup, long eventTime,
+ @GoToSleepReason int reason, int uid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "sleepPowerGroup: eventTime=" + eventTime + ", uid=" + uid);
+ Slog.d(TAG, "sleepPowerGroup: eventTime=" + eventTime
+ + ", groupId=" + powerGroup.getGroupId()
+ + ", reason=" + PowerManager.sleepReasonToString(reason) + ", uid=" + uid);
}
if (!mBootCompleted || !mSystemReady) {
return false;
@@ -2122,7 +2128,10 @@
case WAKEFULNESS_DOZING:
traceMethodName = "goToSleep";
Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
- + " (uid " + uid + ")...");
+ + " (uid " + uid + ", screenOffTimeout=" + mScreenOffTimeoutSetting
+ + ", activityTimeoutWM=" + mUserActivityTimeoutOverrideFromWindowManager
+ + ", maxDimRatio=" + mMaximumScreenDimRatioConfig
+ + ", maxDimDur=" + mMaximumScreenDimDurationConfig + ")...");
mLastGlobalSleepTime = eventTime;
mLastGlobalSleepReason = reason;
@@ -4207,7 +4216,7 @@
void onUserActivity() {
synchronized (mLock) {
mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP).setLastUserActivityTimeLocked(
- mClock.uptimeMillis());
+ mClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_OTHER);
}
}
@@ -5590,7 +5599,8 @@
}
@Override // Binder call
- public void userActivity(int displayId, long eventTime, int event, int flags) {
+ public void userActivity(int displayId, long eventTime,
+ @PowerManager.UserActivityEvent int event, int flags) {
final long now = mClock.uptimeMillis();
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 8916549..d2413f0 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -1,5 +1,6 @@
package com.android.server.wm;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.ActivityManager.processStateAmToProto;
@@ -69,6 +70,7 @@
import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_REVERT_TREATMENT;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
+import static com.android.server.am.ProcessList.INVALID_ADJ;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -274,6 +276,10 @@
final boolean mProcessRunning;
/** whether the process of the launching activity didn't have any active activity. */
final boolean mProcessSwitch;
+ /** The process state of the launching activity prior to the launch */
+ final int mProcessState;
+ /** The oom adj score of the launching activity prior to the launch */
+ final int mProcessOomAdj;
/** Whether the last launched activity has reported drawn. */
boolean mIsDrawn;
/** The latest activity to have been launched. */
@@ -309,8 +315,8 @@
@Nullable
static TransitionInfo create(@NonNull ActivityRecord r,
@NonNull LaunchingState launchingState, @Nullable ActivityOptions options,
- boolean processRunning, boolean processSwitch, boolean newActivityCreated,
- int startResult) {
+ boolean processRunning, boolean processSwitch, int processState, int processOomAdj,
+ boolean newActivityCreated, int startResult) {
if (startResult != START_SUCCESS && startResult != START_TASK_TO_FRONT) {
return null;
}
@@ -325,18 +331,20 @@
transitionType = TYPE_TRANSITION_COLD_LAUNCH;
}
return new TransitionInfo(r, launchingState, options, transitionType, processRunning,
- processSwitch);
+ processSwitch, processState, processOomAdj);
}
/** Use {@link TransitionInfo#create} instead to ensure the transition type is valid. */
private TransitionInfo(ActivityRecord r, LaunchingState launchingState,
ActivityOptions options, int transitionType, boolean processRunning,
- boolean processSwitch) {
+ boolean processSwitch, int processState, int processOomAdj) {
mLaunchingState = launchingState;
mTransitionStartTimeNs = launchingState.mCurrentTransitionStartTimeNs;
mTransitionType = transitionType;
mProcessRunning = processRunning;
mProcessSwitch = processSwitch;
+ mProcessState = processState;
+ mProcessOomAdj = processOomAdj;
mTransitionDeviceUptimeMs = launchingState.mCurrentUpTimeMs;
setLatestLaunchedActivity(r);
// The launching state can be reused by consecutive launch. Its original association
@@ -640,12 +648,23 @@
// interesting.
final boolean processSwitch = !processRunning
|| !processRecord.hasStartedActivity(launchedActivity);
+ final int processState;
+ final int processOomAdj;
+ if (processRunning) {
+ processState = processRecord.getCurrentProcState();
+ processOomAdj = processRecord.getCurrentAdj();
+ } else {
+ processState = PROCESS_STATE_NONEXISTENT;
+ processOomAdj = INVALID_ADJ;
+ }
final TransitionInfo info = launchingState.mAssociatedTransitionInfo;
if (DEBUG_METRICS) {
Slog.i(TAG, "notifyActivityLaunched" + " resultCode=" + resultCode
+ " launchedActivity=" + launchedActivity + " processRunning=" + processRunning
+ " processSwitch=" + processSwitch
+ + " processState=" + processState
+ + " processOomAdj=" + processOomAdj
+ " newActivityCreated=" + newActivityCreated + " info=" + info);
}
@@ -681,7 +700,8 @@
}
final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
- options, processRunning, processSwitch, newActivityCreated, resultCode);
+ options, processRunning, processSwitch, processState, processOomAdj,
+ newActivityCreated, resultCode);
if (newInfo == null) {
abort(launchingState, "unrecognized launch");
return;
@@ -995,8 +1015,11 @@
final long timestamp = info.mTransitionStartTimeNs;
final long uptime = info.mTransitionDeviceUptimeMs;
final int transitionDelay = info.mCurrentTransitionDelayMs;
+ final int processState = info.mProcessState;
+ final int processOomAdj = info.mProcessOomAdj;
mLoggerHandler.post(() -> logAppTransition(
- timestamp, uptime, transitionDelay, infoSnapshot, isHibernating));
+ timestamp, uptime, transitionDelay, infoSnapshot, isHibernating,
+ processState, processOomAdj));
}
mLoggerHandler.post(() -> logAppDisplayed(infoSnapshot));
if (info.mPendingFullyDrawn != null) {
@@ -1008,7 +1031,8 @@
// This gets called on another thread without holding the activity manager lock.
private void logAppTransition(long transitionStartTimeNs, long transitionDeviceUptimeMs,
- int currentTransitionDelayMs, TransitionInfoSnapshot info, boolean isHibernating) {
+ int currentTransitionDelayMs, TransitionInfoSnapshot info, boolean isHibernating,
+ int processState, int processOomAdj) {
final LogMaker builder = new LogMaker(APP_TRANSITION);
builder.setPackageName(info.packageName);
builder.setType(info.type);
@@ -1074,7 +1098,9 @@
isIncremental,
isLoading,
info.launchedActivityName.hashCode(),
- TimeUnit.NANOSECONDS.toMillis(transitionStartTimeNs));
+ TimeUnit.NANOSECONDS.toMillis(transitionStartTimeNs),
+ processState,
+ processOomAdj);
if (DEBUG_METRICS) {
Slog.i(TAG, String.format("APP_START_OCCURRED(%s, %s, %s, %s, %s)",
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 208450d..2e30962 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -660,6 +660,9 @@
boolean mUseTransferredAnimation;
+ /** Whether we need to setup the animation to animate only within the letterbox. */
+ private boolean mNeedsLetterboxedAnimation;
+
/**
* @see #currentLaunchCanTurnScreenOn()
*/
@@ -1566,7 +1569,7 @@
if (task == mLastParentBeforePip && task != null) {
// Notify the TaskFragmentOrganizer that the activity is reparented back from pip.
mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController
- .onActivityReparentToTask(this);
+ .onActivityReparentedToTask(this);
// Activity's reparented back from pip, clear the links once established
clearLastParentBeforePip();
}
@@ -1762,8 +1765,12 @@
mLetterboxUiController.layoutLetterbox(winHint);
}
- boolean hasWallpaperBackgroudForLetterbox() {
- return mLetterboxUiController.hasWallpaperBackgroudForLetterbox();
+ boolean hasWallpaperBackgroundForLetterbox() {
+ return mLetterboxUiController.hasWallpaperBackgroundForLetterbox();
+ }
+
+ void updateLetterboxSurface(WindowState winHint, Transaction t) {
+ mLetterboxUiController.updateLetterboxSurface(winHint, t);
}
void updateLetterboxSurface(WindowState winHint) {
@@ -5334,6 +5341,18 @@
commitVisibility(visible, performLayout, false /* fromTransition */);
}
+ void setNeedsLetterboxedAnimation(boolean needsLetterboxedAnimation) {
+ mNeedsLetterboxedAnimation = needsLetterboxedAnimation;
+ }
+
+ boolean isNeedsLetterboxedAnimation() {
+ return mNeedsLetterboxedAnimation;
+ }
+
+ boolean isInLetterboxAnimation() {
+ return mNeedsLetterboxedAnimation && isAnimating();
+ }
+
/**
* Post process after applying an app transition animation.
*
@@ -7261,6 +7280,10 @@
.setParent(getAnimationLeashParent())
.setName(getSurfaceControl() + " - animation-bounds")
.setCallsite("ActivityRecord.createAnimationBoundsLayer");
+ if (mNeedsLetterboxedAnimation) {
+ // Needs to be an effect layer to support rounded corners
+ builder.setEffectLayer();
+ }
final SurfaceControl boundsLayer = builder.build();
t.show(boundsLayer);
return boundsLayer;
@@ -7298,6 +7321,11 @@
mAnimatingActivityRegistry.notifyStarting(this);
}
+ if (mNeedsLetterboxedAnimation) {
+ updateLetterboxSurface(findMainWindow(), t);
+ mNeedsAnimationBoundsLayer = true;
+ }
+
// If the animation needs to be cropped then an animation bounds layer is created as a
// child of the root pinned task or animation layer. The leash is then reparented to this
// new layer.
@@ -7320,6 +7348,17 @@
t.setLayer(leash, 0);
t.setLayer(mAnimationBoundsLayer, getLastLayer());
+ if (mNeedsLetterboxedAnimation) {
+ final int cornerRadius = mLetterboxUiController
+ .getRoundedCornersRadius(findMainWindow());
+
+ final Rect letterboxInnerBounds = new Rect();
+ getLetterboxInnerBounds(letterboxInnerBounds);
+
+ t.setCornerRadius(mAnimationBoundsLayer, cornerRadius)
+ .setCrop(mAnimationBoundsLayer, letterboxInnerBounds);
+ }
+
// Reparent leash to animation bounds layer.
t.reparent(leash, mAnimationBoundsLayer);
}
@@ -7433,6 +7472,12 @@
mAnimationBoundsLayer = null;
}
+ mNeedsAnimationBoundsLayer = false;
+ if (mNeedsLetterboxedAnimation) {
+ mNeedsLetterboxedAnimation = false;
+ updateLetterboxSurface(findMainWindow(), t);
+ }
+
if (mAnimatingActivityRegistry != null) {
mAnimatingActivityRegistry.notifyFinished(this);
}
@@ -7445,7 +7490,6 @@
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished");
mTransit = TRANSIT_OLD_UNSET;
mTransitFlags = 0;
- mNeedsAnimationBoundsLayer = false;
setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
"ActivityRecord");
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7323718..69debf4 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -311,7 +311,7 @@
/**
* The duration to keep a process in animating state (top scheduling group) when the
- * wakefulness is changing from awake to doze or sleep.
+ * wakefulness is dozing (unlocking) or changing from awake to doze or sleep (locking).
*/
private static final long DOZE_ANIMATING_STATE_RETAIN_TIME_MS = 2000;
@@ -1486,6 +1486,7 @@
a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
a.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ a.configChanges = ActivityInfo.CONFIG_ORIENTATION;
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchActivityType(ACTIVITY_TYPE_DREAM);
@@ -2927,12 +2928,14 @@
mDemoteTopAppReasons &= ~DEMOTE_TOP_REASON_DURING_UNLOCKING;
final WindowState notificationShade = mRootWindowContainer.getDefaultDisplay()
.getDisplayPolicy().getNotificationShade();
- proc = notificationShade != null
- ? mProcessMap.getProcess(notificationShade.mSession.mPid) : null;
+ proc = notificationShade != null ? notificationShade.getProcess() : null;
}
- if (proc == null) {
- return;
- }
+ setProcessAnimatingWhileDozing(proc);
+ }
+
+ // The caller MUST NOT hold the global lock because it calls AM method directly.
+ void setProcessAnimatingWhileDozing(WindowProcessController proc) {
+ if (proc == null) return;
// Set to activity manager directly to make sure the state can be seen by the subsequent
// update of scheduling group.
proc.setRunningAnimationUnsafe();
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index fb9d7e6..5ac5f2e 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -81,9 +81,11 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.Rect;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Pair;
import android.util.Slog;
import android.view.Display;
import android.view.RemoteAnimationAdapter;
@@ -1028,6 +1030,32 @@
return;
}
+ if (AppTransition.isActivityTransitOld(transit)) {
+ final ArrayList<Pair<ActivityRecord, Rect>> closingLetterboxes = new ArrayList();
+ for (int i = 0; i < closingApps.size(); ++i) {
+ ActivityRecord closingApp = closingApps.valueAt(i);
+ if (closingApp.areBoundsLetterboxed()) {
+ final Rect insets = closingApp.getLetterboxInsets();
+ closingLetterboxes.add(new Pair(closingApp, insets));
+ }
+ }
+
+ for (int i = 0; i < openingApps.size(); ++i) {
+ ActivityRecord openingApp = openingApps.valueAt(i);
+ if (openingApp.areBoundsLetterboxed()) {
+ final Rect openingInsets = openingApp.getLetterboxInsets();
+ for (Pair<ActivityRecord, Rect> closingLetterbox : closingLetterboxes) {
+ final Rect closingInsets = closingLetterbox.second;
+ if (openingInsets.equals(closingInsets)) {
+ ActivityRecord closingApp = closingLetterbox.first;
+ openingApp.setNeedsLetterboxedAnimation(true);
+ closingApp.setNeedsLetterboxedAnimation(true);
+ }
+ }
+ }
+ }
+ }
+
final ArraySet<WindowContainer> openingWcs = getAnimationTargets(
openingApps, closingApps, true /* visible */);
final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 0422906..b033dca 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -504,6 +504,7 @@
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
+ mTransitionController.collectForDisplayAreaChange(this);
mTmpConfiguration.setTo(getConfiguration());
super.onConfigurationChanged(newParentConfig);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ecb9fe3..b645254 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -946,7 +946,7 @@
final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
.getPreferredModeId(w);
- if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
+ if (w.isFocused() && mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
&& preferredModeId != 0) {
mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId;
}
@@ -5935,6 +5935,9 @@
if (changes != 0) {
Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
+ mTempConfig + " for displayId=" + mDisplayId);
+ if (isReady() && mTransitionController.isShellTransitionsEnabled()) {
+ requestChangeTransitionIfNeeded(changes, null /* displayChange */);
+ }
onRequestedOverrideConfigurationChanged(mTempConfig);
final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
@@ -5951,9 +5954,6 @@
}
mWmService.mDisplayNotificationController.dispatchDisplayChanged(
this, getConfiguration());
- if (isReady() && mTransitionController.isShellTransitionsEnabled()) {
- requestChangeTransitionIfNeeded(changes, null /* displayChange */);
- }
}
return changes;
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 5221072..1a34c93 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -258,7 +258,7 @@
private volatile boolean mWindowManagerDrawComplete;
private WindowState mStatusBar = null;
- private WindowState mNotificationShade = null;
+ private volatile WindowState mNotificationShade;
private final int[] mStatusBarHeightForRotation = new int[4];
private WindowState mNavigationBar = null;
@NavigationBarPosition
@@ -794,11 +794,11 @@
}
public void setAwake(boolean awake) {
- if (awake == mAwake) {
- return;
- }
- mAwake = awake;
- synchronized (mService.mGlobalLock) {
+ synchronized (mLock) {
+ if (awake == mAwake) {
+ return;
+ }
+ mAwake = awake;
if (!mDisplayContent.isDefaultDisplay) {
return;
}
@@ -2371,18 +2371,19 @@
return;
}
- // The immersive mode confirmation should never affect the system bar visibility, otherwise
+ // Immersive mode confirmation should never affect the system bar visibility, otherwise
// it will unhide the navigation bar and hide itself.
if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
-
- // The immersive mode confirmation took the focus from mLastFocusedWindow which was
- // controlling the system ui visibility. So if mLastFocusedWindow can still receive
- // keys, we let it keep controlling the visibility.
- final boolean lastFocusCanReceiveKeys =
- (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
- winCandidate = isKeyguardShowing() && !isKeyguardOccluded() ? mNotificationShade
- : lastFocusCanReceiveKeys ? mLastFocusedWindow
- : mTopFullscreenOpaqueWindowState;
+ if (mNotificationShade != null && mNotificationShade.canReceiveKeys()) {
+ // Let notification shade control the system bar visibility.
+ winCandidate = mNotificationShade;
+ } else if (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys()) {
+ // Immersive mode confirmation took the focus from mLastFocusedWindow which was
+ // controlling the system bar visibility. Let it keep controlling the visibility.
+ winCandidate = mLastFocusedWindow;
+ } else {
+ winCandidate = mTopFullscreenOpaqueWindowState;
+ }
if (winCandidate == null) {
return;
}
@@ -2745,6 +2746,19 @@
mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
}
+ /** Called when a {@link android.os.PowerManager#USER_ACTIVITY_EVENT_TOUCH} is sent. */
+ public void onUserActivityEventTouch() {
+ // If there is keyguard, it may use INPUT_FEATURE_DISABLE_USER_ACTIVITY (InputDispatcher
+ // won't trigger user activity for touch). So while the device is not interactive, the user
+ // event is only sent explicitly from SystemUI.
+ if (mAwake) return;
+ // If the event is triggered while the display is not awake, the screen may be showing
+ // dozing UI such as AOD or overlay UI of under display fingerprint. Then set the animating
+ // state temporarily to make the process more responsive.
+ final WindowState w = mNotificationShade;
+ mService.mAtmService.setProcessAnimatingWhileDozing(w != null ? w.getProcess() : null);
+ }
+
boolean onSystemUiSettingsChanged() {
return mImmersiveModeConfirmation.onSettingChanged(mService.mCurrentUserId);
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 8dd5850..97609a7 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -513,19 +513,6 @@
return true;
}
- /**
- * Utility to get a rotating displaycontent from a Transition.
- * @return null if the transition doesn't contain a rotating display.
- */
- static DisplayContent getDisplayFromTransition(Transition transition) {
- for (int i = transition.mParticipants.size() - 1; i >= 0; --i) {
- final WindowContainer wc = transition.mParticipants.valueAt(i);
- if (!(wc instanceof DisplayContent)) continue;
- return (DisplayContent) wc;
- }
- return null;
- }
-
private void startRemoteRotation(int fromRotation, int toRotation) {
mDisplayContent.mRemoteDisplayChangeController.performRemoteDisplayChange(
fromRotation, toRotation, null /* newDisplayAreaInfo */,
@@ -545,11 +532,6 @@
throw new IllegalStateException("Trying to rotate outside a transition");
}
mDisplayContent.mTransitionController.collect(mDisplayContent);
- // Go through all tasks and collect them before the rotation
- // TODO(shell-transitions): move collect() to onConfigurationChange once wallpaper
- // handling is synchronized.
- mDisplayContent.mTransitionController.collectForDisplayAreaChange(mDisplayContent,
- null /* use collecting transition */);
}
mService.mAtmService.deferWindowLayout();
try {
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 3e2d7c9..506396a 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -759,7 +759,7 @@
InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) {
super(show, false /* hasCallbacks */, types, BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
- false /* disable */, 0 /* floatingImeBottomInsets */);
+ false /* disable */, 0 /* floatingImeBottomInsets */, null);
mFinishCallback = finishCallback;
mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
}
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index df3109a..27550d9 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -56,6 +56,7 @@
private final Supplier<Boolean> mHasWallpaperBackgroundSupplier;
private final Supplier<Integer> mBlurRadiusSupplier;
private final Supplier<Float> mDarkScrimAlphaSupplier;
+ private final Supplier<SurfaceControl> mParentSurfaceSupplier;
private final Rect mOuter = new Rect();
private final Rect mInner = new Rect();
@@ -87,7 +88,8 @@
Supplier<Integer> blurRadiusSupplier,
Supplier<Float> darkScrimAlphaSupplier,
IntConsumer doubleTapCallbackX,
- IntConsumer doubleTapCallbackY) {
+ IntConsumer doubleTapCallbackY,
+ Supplier<SurfaceControl> parentSurface) {
mSurfaceControlFactory = surfaceControlFactory;
mTransactionFactory = transactionFactory;
mAreCornersRounded = areCornersRounded;
@@ -97,6 +99,7 @@
mDarkScrimAlphaSupplier = darkScrimAlphaSupplier;
mDoubleTapCallbackX = doubleTapCallbackX;
mDoubleTapCallbackY = doubleTapCallbackY;
+ mParentSurfaceSupplier = parentSurface;
}
/**
@@ -121,7 +124,6 @@
mFullWindowSurface.layout(outer.left, outer.top, outer.right, outer.bottom, surfaceOrigin);
}
-
/**
* Gets the insets between the outer and inner rects.
*/
@@ -333,6 +335,7 @@
private SurfaceControl mSurface;
private Color mColor;
private boolean mHasWallpaperBackground;
+ private SurfaceControl mParentSurface;
private final Rect mSurfaceFrameRelative = new Rect();
private final Rect mLayoutFrameGlobal = new Rect();
@@ -403,10 +406,12 @@
}
mColor = mColorSupplier.get();
+ mParentSurface = mParentSurfaceSupplier.get();
t.setColor(mSurface, getRgbColorArray());
t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top);
t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(),
mSurfaceFrameRelative.height());
+ t.reparent(mSurface, mParentSurface);
mHasWallpaperBackground = mHasWallpaperBackgroundSupplier.get();
updateAlphaAndBlur(t);
@@ -452,12 +457,13 @@
public boolean needsApplySurfaceChanges() {
return !mSurfaceFrameRelative.equals(mLayoutFrameRelative)
- // If mSurfaceFrameRelative is empty then mHasWallpaperBackground and mColor
- // may never be updated in applySurfaceChanges but this doesn't mean that
- // update is needed.
+ // If mSurfaceFrameRelative is empty then mHasWallpaperBackground, mColor,
+ // and mParentSurface may never be updated in applySurfaceChanges but this
+ // doesn't mean that update is needed.
|| !mSurfaceFrameRelative.isEmpty()
&& (mHasWallpaperBackgroundSupplier.get() != mHasWallpaperBackground
- || !mColorSupplier.get().equals(mColor));
+ || !mColorSupplier.get().equals(mColor)
+ || mParentSurfaceSupplier.get() != mParentSurface);
}
}
}
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index 57c60f4..a469c6b 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -265,7 +265,7 @@
}
/**
- * Overrides corners raidus for activities presented in the letterbox mode. If given value < 0,
+ * Overrides corners radius for activities presented in the letterbox mode. If given value < 0,
* both it and a value of {@link
* com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and
* corners of the activity won't be rounded.
@@ -275,7 +275,7 @@
}
/**
- * Resets corners raidus for activities presented in the letterbox mode to {@link
+ * Resets corners radius for activities presented in the letterbox mode to {@link
* com.android.internal.R.integer.config_letterboxActivityCornersRadius}.
*/
void resetLetterboxActivityCornersRadius() {
@@ -291,7 +291,7 @@
}
/**
- * Gets corners raidus for activities presented in the letterbox mode.
+ * Gets corners radius for activities presented in the letterbox mode.
*/
int getLetterboxActivityCornersRadius() {
return mLetterboxActivityCornersRadius;
@@ -318,7 +318,7 @@
/**
* Sets color of letterbox background which is used when {@link
* #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
- * fallback for other backfround types.
+ * fallback for other background types.
*/
void setLetterboxBackgroundColor(Color color) {
mLetterboxBackgroundColorOverride = color;
@@ -327,7 +327,7 @@
/**
* Sets color ID of letterbox background which is used when {@link
* #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as
- * fallback for other backfround types.
+ * fallback for other background types.
*/
void setLetterboxBackgroundColorResourceId(int colorId) {
mLetterboxBackgroundColorResourceIdOverride = colorId;
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index c8ed602..317c93e 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -89,7 +89,7 @@
// Taskbar expanded height. Used to determine whether to crop an app window to display rounded
// corners above the taskbar.
- private float mExpandedTaskBarHeight;
+ private final float mExpandedTaskBarHeight;
private boolean mShowWallpaperForLetterboxBackground;
@@ -120,7 +120,7 @@
}
}
- boolean hasWallpaperBackgroudForLetterbox() {
+ boolean hasWallpaperBackgroundForLetterbox() {
return mShowWallpaperForLetterboxBackground;
}
@@ -137,6 +137,11 @@
void getLetterboxInnerBounds(Rect outBounds) {
if (mLetterbox != null) {
outBounds.set(mLetterbox.getInnerFrame());
+ final WindowState w = mActivityRecord.findMainWindow();
+ if (w == null) {
+ return;
+ }
+ adjustBoundsForTaskbar(w, outBounds);
} else {
outBounds.setEmpty();
}
@@ -160,13 +165,17 @@
}
void updateLetterboxSurface(WindowState winHint) {
+ updateLetterboxSurface(winHint, mActivityRecord.getSyncTransaction());
+ }
+
+ void updateLetterboxSurface(WindowState winHint, Transaction t) {
final WindowState w = mActivityRecord.findMainWindow();
if (w != winHint && winHint != null && w != null) {
return;
}
layoutLetterbox(winHint);
if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) {
- mLetterbox.applySurfaceChanges(mActivityRecord.getSyncTransaction());
+ mLetterbox.applySurfaceChanges(t);
}
}
@@ -191,14 +200,22 @@
mActivityRecord.mWmService.mTransactionFactory,
this::shouldLetterboxHaveRoundedCorners,
this::getLetterboxBackgroundColor,
- this::hasWallpaperBackgroudForLetterbox,
+ this::hasWallpaperBackgroundForLetterbox,
this::getLetterboxWallpaperBlurRadius,
this::getLetterboxWallpaperDarkScrimAlpha,
this::handleHorizontalDoubleTap,
- this::handleVerticalDoubleTap);
+ this::handleVerticalDoubleTap,
+ this::getLetterboxParentSurface);
mLetterbox.attachInput(w);
}
- mActivityRecord.getPosition(mTmpPoint);
+
+ if (mActivityRecord.isInLetterboxAnimation()) {
+ // In this case we attach the letterbox to the task instead of the activity.
+ mActivityRecord.getTask().getPosition(mTmpPoint);
+ } else {
+ mActivityRecord.getPosition(mTmpPoint);
+ }
+
// Get the bounds of the "space-to-fill". The transformed bounds have the highest
// priority because the activity is launched in a rotated environment. In multi-window
// mode, the task-level represents this. In fullscreen-mode, the task container does
@@ -215,6 +232,13 @@
}
}
+ SurfaceControl getLetterboxParentSurface() {
+ if (mActivityRecord.isInLetterboxAnimation()) {
+ return mActivityRecord.getTask().getSurfaceControl();
+ }
+ return mActivityRecord.getSurfaceControl();
+ }
+
private boolean shouldLetterboxHaveRoundedCorners() {
// TODO(b/214030873): remove once background is drawn for transparent activities
// Letterbox shouldn't have rounded corners if the activity is transparent
@@ -436,7 +460,7 @@
}
break;
case LETTERBOX_BACKGROUND_WALLPAPER:
- if (hasWallpaperBackgroudForLetterbox()) {
+ if (hasWallpaperBackgroundForLetterbox()) {
// Color is used for translucent scrim that dims wallpaper.
return Color.valueOf(Color.BLACK);
}
@@ -459,15 +483,14 @@
private void updateRoundedCorners(WindowState mainWindow) {
final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface();
if (windowSurface != null && windowSurface.isValid()) {
- Transaction transaction = mActivityRecord.getSyncTransaction();
+ final Transaction transaction = mActivityRecord.getSyncTransaction();
- final InsetsState insetsState = mainWindow.getInsetsState();
- final InsetsSource taskbarInsetsSource =
- insetsState.peekSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
-
- if (!isLetterboxedNotForDisplayCutout(mainWindow)
- || !mLetterboxConfiguration.isLetterboxActivityCornersRounded()
- || taskbarInsetsSource == null) {
+ if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) {
+ // We don't want corner radius on the window.
+ // In the case the ActivityRecord requires a letterboxed animation we never want
+ // rounded corners on the window because rounded corners are applied at the
+ // animation-bounds surface level and rounded corners on the window would interfere
+ // with that leading to unexpected rounded corner positioning during the animation.
transaction
.setWindowCrop(windowSurface, null)
.setCornerRadius(windowSurface, 0);
@@ -476,48 +499,89 @@
Rect cropBounds = null;
- // Rounded corners should be displayed above the taskbar. When taskbar is hidden,
- // an insets frame is equal to a navigation bar which shouldn't affect position of
- // rounded corners since apps are expected to handle navigation bar inset.
- // This condition checks whether the taskbar is visible.
- // Do not crop the taskbar inset if the window is in immersive mode - the user can
- // swipe to show/hide the taskbar as an overlay.
- if (taskbarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight
- && taskbarInsetsSource.isVisible()) {
+ if (hasVisibleTaskbar(mainWindow)) {
cropBounds = new Rect(mActivityRecord.getBounds());
// Activity bounds are in screen coordinates while (0,0) for activity's surface
// control is at the top left corner of an app window so offsetting bounds
// accordingly.
cropBounds.offsetTo(0, 0);
- // Rounded cornerners should be displayed above the taskbar.
- cropBounds.bottom =
- Math.min(cropBounds.bottom, taskbarInsetsSource.getFrame().top);
- if (mActivityRecord.inSizeCompatMode()
- && mActivityRecord.getSizeCompatScale() < 1.0f) {
- cropBounds.scale(1.0f / mActivityRecord.getSizeCompatScale());
- }
+ // Rounded corners should be displayed above the taskbar.
+ adjustBoundsForTaskbarUnchecked(mainWindow, cropBounds);
}
transaction
.setWindowCrop(windowSurface, cropBounds)
- .setCornerRadius(windowSurface, getRoundedCorners(insetsState));
+ .setCornerRadius(windowSurface, getRoundedCornersRadius(mainWindow));
}
}
- // Returns rounded corners radius based on override in
+ private boolean requiresRoundedCorners(WindowState mainWindow) {
+ final InsetsSource taskbarInsetsSource = getTaskbarInsetsSource(mainWindow);
+
+ return isLetterboxedNotForDisplayCutout(mainWindow)
+ && mLetterboxConfiguration.isLetterboxActivityCornersRounded()
+ && taskbarInsetsSource != null;
+ }
+
+ // Returns rounded corners radius the letterboxed activity should have based on override in
// R.integer.config_letterboxActivityCornersRadius or min device bottom corner radii.
// Device corners can be different on the right and left sides but we use the same radius
// for all corners for consistency and pick a minimal bottom one for consistency with a
// taskbar rounded corners.
- private int getRoundedCorners(InsetsState insetsState) {
+ int getRoundedCornersRadius(WindowState mainWindow) {
+ if (!requiresRoundedCorners(mainWindow)) {
+ return 0;
+ }
+
if (mLetterboxConfiguration.getLetterboxActivityCornersRadius() >= 0) {
return mLetterboxConfiguration.getLetterboxActivityCornersRadius();
}
+
+ final InsetsState insetsState = mainWindow.getInsetsState();
return Math.min(
getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_LEFT),
getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_RIGHT));
}
+ /**
+ * Returns whether the taskbar is visible. Returns false if the window is in immersive mode,
+ * since the user can swipe to show/hide the taskbar as an overlay.
+ */
+ private boolean hasVisibleTaskbar(WindowState mainWindow) {
+ final InsetsSource taskbarInsetsSource = getTaskbarInsetsSource(mainWindow);
+
+ return taskbarInsetsSource != null
+ && taskbarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight
+ && taskbarInsetsSource.isVisible();
+ }
+
+ private InsetsSource getTaskbarInsetsSource(WindowState mainWindow) {
+ final InsetsState insetsState = mainWindow.getInsetsState();
+ return insetsState.peekSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+ }
+
+ private void adjustBoundsForTaskbar(WindowState mainWindow, Rect bounds) {
+ // Rounded corners should be displayed above the taskbar. When taskbar is hidden,
+ // an insets frame is equal to a navigation bar which shouldn't affect position of
+ // rounded corners since apps are expected to handle navigation bar inset.
+ // This condition checks whether the taskbar is visible.
+ // Do not crop the taskbar inset if the window is in immersive mode - the user can
+ // swipe to show/hide the taskbar as an overlay.
+ if (hasVisibleTaskbar(mainWindow)) {
+ adjustBoundsForTaskbarUnchecked(mainWindow, bounds);
+ }
+ }
+
+ private void adjustBoundsForTaskbarUnchecked(WindowState mainWindow, Rect bounds) {
+ // Rounded corners should be displayed above the taskbar.
+ bounds.bottom =
+ Math.min(bounds.bottom, getTaskbarInsetsSource(mainWindow).getFrame().top);
+ if (mActivityRecord.inSizeCompatMode()
+ && mActivityRecord.getSizeCompatScale() < 1.0f) {
+ bounds.scale(1.0f / mActivityRecord.getSizeCompatScale());
+ }
+ }
+
private int getInsetsStateCornerRadius(
InsetsState insetsState, @RoundedCorner.Position int position) {
RoundedCorner corner = insetsState.getRoundedCorners().getRoundedCorner(position);
@@ -592,7 +656,7 @@
+ letterboxBackgroundTypeToString(
mLetterboxConfiguration.getLetterboxBackgroundType()));
pw.println(prefix + " letterboxCornerRadius="
- + getRoundedCorners(mainWin.getInsetsState()));
+ + getRoundedCornersRadius(mainWin));
if (mLetterboxConfiguration.getLetterboxBackgroundType()
== LETTERBOX_BACKGROUND_WALLPAPER) {
pw.println(prefix + " isLetterboxWallpaperBlurSupported="
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 64749cf..a89894d 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -101,7 +101,6 @@
if (t != null) {
mDisplayContent.mAtmService.startLaunchPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY);
- mTransitionController.collectForDisplayAreaChange(mDisplayContent, t);
mTransition = t;
}
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index c7f8a1e..f3670e4 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -27,7 +27,10 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
import android.graphics.Insets;
+import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.power.Boost;
@@ -374,43 +377,45 @@
final int targetSurfaceWidth = bounds.width();
if (maxExtensionInsets.left < 0) {
- final Rect edgeBounds = new Rect(0, 0, 1, targetSurfaceHeight);
+ final Rect edgeBounds = new Rect(bounds.left, bounds.top, bounds.left + 1,
+ bounds.bottom);
final Rect extensionRect = new Rect(0, 0,
-maxExtensionInsets.left, targetSurfaceHeight);
- final int xPos = maxExtensionInsets.left;
- final int yPos = 0;
+ final int xPos = bounds.left + maxExtensionInsets.left;
+ final int yPos = bounds.top;
createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Left Edge Extension", transaction);
}
if (maxExtensionInsets.top < 0) {
- final Rect edgeBounds = new Rect(0, 0, targetSurfaceWidth, 1);
+ final Rect edgeBounds = new Rect(bounds.left, bounds.top, targetSurfaceWidth,
+ bounds.top + 1);
final Rect extensionRect = new Rect(0, 0,
targetSurfaceWidth, -maxExtensionInsets.top);
- final int xPos = 0;
- final int yPos = maxExtensionInsets.top;
+ final int xPos = bounds.left;
+ final int yPos = bounds.top + maxExtensionInsets.top;
createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Top Edge Extension", transaction);
}
if (maxExtensionInsets.right < 0) {
- final Rect edgeBounds = new Rect(targetSurfaceWidth - 1, 0,
- targetSurfaceWidth, targetSurfaceHeight);
+ final Rect edgeBounds = new Rect(bounds.right - 1, bounds.top, bounds.right,
+ bounds.bottom);
final Rect extensionRect = new Rect(0, 0,
-maxExtensionInsets.right, targetSurfaceHeight);
- final int xPos = targetSurfaceWidth;
- final int yPos = 0;
+ final int xPos = bounds.right;
+ final int yPos = bounds.top;
createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Right Edge Extension", transaction);
}
if (maxExtensionInsets.bottom < 0) {
- final Rect edgeBounds = new Rect(0, targetSurfaceHeight - 1,
- targetSurfaceWidth, targetSurfaceHeight);
+ final Rect edgeBounds = new Rect(bounds.left, bounds.bottom - 1,
+ bounds.right, bounds.bottom);
final Rect extensionRect = new Rect(0, 0,
targetSurfaceWidth, -maxExtensionInsets.bottom);
- final int xPos = maxExtensionInsets.left;
- final int yPos = targetSurfaceHeight;
+ final int xPos = bounds.left;
+ final int yPos = bounds.bottom;
createExtensionSurface(leash, edgeBounds,
extensionRect, xPos, yPos, "Bottom Edge Extension", transaction);
}
@@ -453,16 +458,20 @@
.setHidden(true)
.setCallsite("DefaultTransitionHandler#startAnimation")
.setOpaque(true)
- .setBufferSize(edgeBounds.width(), edgeBounds.height())
+ .setBufferSize(extensionRect.width(), extensionRect.height())
.build();
- final Surface surface = new Surface(edgeExtensionLayer);
- surface.attachAndQueueBufferWithColorSpace(edgeBuffer.getHardwareBuffer(),
- edgeBuffer.getColorSpace());
- surface.release();
+ BitmapShader shader = new BitmapShader(edgeBuffer.asBitmap(),
+ android.graphics.Shader.TileMode.CLAMP,
+ android.graphics.Shader.TileMode.CLAMP);
+ final Paint paint = new Paint();
+ paint.setShader(shader);
- final float scaleX = getScaleXForExtensionSurface(edgeBounds, extensionRect);
- final float scaleY = getScaleYForExtensionSurface(edgeBounds, extensionRect);
+ final Surface surface = new Surface(edgeExtensionLayer);
+ Canvas c = surface.lockHardwareCanvas();
+ c.drawRect(extensionRect, paint);
+ surface.unlockCanvasAndPost(c);
+ surface.release();
synchronized (mEdgeExtensionLock) {
if (!mEdgeExtensions.containsKey(leash)) {
@@ -472,7 +481,6 @@
return;
}
- startTransaction.setScale(edgeExtensionLayer, scaleX, scaleY);
startTransaction.reparent(edgeExtensionLayer, leash);
startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE);
startTransaction.setPosition(edgeExtensionLayer, xPos, yPos);
@@ -508,8 +516,6 @@
throw new RuntimeException("Unexpected edgeBounds and extensionRect heights");
}
-
-
private static final class RunningAnimation {
final AnimationSpec mAnimSpec;
final SurfaceControl mLeash;
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 5f85a14..f3f2110 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -2340,7 +2340,10 @@
return false;
}
- return !startBounds.equals(getBounds());
+ // Only take snapshot if the bounds are resized.
+ final Rect endBounds = getConfiguration().windowConfiguration.getBounds();
+ return endBounds.width() != startBounds.width()
+ || endBounds.height() != startBounds.height();
}
boolean canHaveEmbeddingActivityTransition(@NonNull ActivityRecord child) {
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 6ca5648..88059e1 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -18,7 +18,7 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.window.TaskFragmentOrganizer.putErrorInfoInBundle;
-import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENT_TO_TASK;
+import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
@@ -277,7 +277,7 @@
}
@Nullable
- TaskFragmentTransaction.Change prepareActivityReparentToTask(
+ TaskFragmentTransaction.Change prepareActivityReparentedToTask(
@NonNull ActivityRecord activity) {
if (activity.finishing) {
Slog.d(TAG, "Reparent activity=" + activity.token + " is finishing");
@@ -315,7 +315,7 @@
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Activity=%s reparent to taskId=%d",
activity.token, task.mTaskId);
- return new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENT_TO_TASK)
+ return new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENTED_TO_TASK)
.setTaskId(task.mTaskId)
.setActivityIntent(activity.intent)
.setActivityToken(activityToken);
@@ -521,7 +521,7 @@
mAtmService.mWindowManager.mWindowPlacerLocked.requestTraversal();
}
- void onActivityReparentToTask(@NonNull ActivityRecord activity) {
+ void onActivityReparentedToTask(@NonNull ActivityRecord activity) {
final ITaskFragmentOrganizer organizer;
if (activity.mLastTaskFragmentOrganizerBeforePip != null) {
// If the activity is previously embedded in an organized TaskFragment.
@@ -547,7 +547,7 @@
return;
}
addPendingEvent(new PendingTaskFragmentEvent.Builder(
- PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENT_TO_TASK, organizer)
+ PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENTED_TO_TASK, organizer)
.setActivity(activity)
.build());
}
@@ -601,7 +601,7 @@
static final int EVENT_INFO_CHANGED = 2;
static final int EVENT_PARENT_INFO_CHANGED = 3;
static final int EVENT_ERROR = 4;
- static final int EVENT_ACTIVITY_REPARENT_TO_TASK = 5;
+ static final int EVENT_ACTIVITY_REPARENTED_TO_TASK = 5;
@IntDef(prefix = "EVENT_", value = {
EVENT_APPEARED,
@@ -609,7 +609,7 @@
EVENT_INFO_CHANGED,
EVENT_PARENT_INFO_CHANGED,
EVENT_ERROR,
- EVENT_ACTIVITY_REPARENT_TO_TASK
+ EVENT_ACTIVITY_REPARENTED_TO_TASK
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {}
@@ -900,8 +900,8 @@
case PendingTaskFragmentEvent.EVENT_ERROR:
return state.prepareTaskFragmentError(event.mErrorCallbackToken, taskFragment,
event.mOpType, event.mException);
- case PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENT_TO_TASK:
- return state.prepareActivityReparentToTask(event.mActivity);
+ case PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENTED_TO_TASK:
+ return state.prepareActivityReparentedToTask(event.mActivity);
default:
throw new IllegalArgumentException("Unknown TaskFragmentEvent=" + event.mEventType);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 584a40e..803890b 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1205,7 +1205,14 @@
return false;
}
- final @TransitionInfo.TransitionMode int mode = changes.get(target).getTransitMode(target);
+ final ChangeInfo change = changes.get(target);
+ if (change.mStartParent != null && target.getParent() != change.mStartParent) {
+ // When a window is reparented, the state change won't fit into any of the parents.
+ // Don't promote such change so that we can animate the reparent if needed.
+ return false;
+ }
+
+ final @TransitionInfo.TransitionMode int mode = change.getTransitMode(target);
for (int i = parent.getChildCount() - 1; i >= 0; --i) {
final WindowContainer<?> sibling = parent.getChildAt(i);
if (target == sibling) continue;
@@ -1345,14 +1352,14 @@
// Intermediate parents must be those that has window to be managed by Shell.
continue;
}
- if (parentChange.mParent != null && !skipIntermediateReports) {
- changes.get(wc).mParent = p;
+ if (parentChange.mEndParent != null && !skipIntermediateReports) {
+ changes.get(wc).mEndParent = p;
// The chain above the parent was processed.
break;
}
if (targetList.contains(p)) {
if (skipIntermediateReports) {
- changes.get(wc).mParent = p;
+ changes.get(wc).mEndParent = p;
} else {
intermediates.add(p);
}
@@ -1364,10 +1371,10 @@
}
if (!foundParentInTargets || intermediates.isEmpty()) continue;
// Add any always-report parents along the way.
- changes.get(wc).mParent = intermediates.get(0);
+ changes.get(wc).mEndParent = intermediates.get(0);
for (int j = 0; j < intermediates.size() - 1; j++) {
final WindowContainer<?> intermediate = intermediates.get(j);
- changes.get(intermediate).mParent = intermediates.get(j + 1);
+ changes.get(intermediate).mEndParent = intermediates.get(j + 1);
targets.add(intermediate);
}
}
@@ -1480,8 +1487,8 @@
target.mRemoteToken != null ? target.mRemoteToken.toWindowContainerToken()
: null, getLeashSurface(target, startT));
// TODO(shell-transitions): Use leash for non-organized windows.
- if (info.mParent != null) {
- change.setParent(info.mParent.mRemoteToken.toWindowContainerToken());
+ if (info.mEndParent != null) {
+ change.setParent(info.mEndParent.mRemoteToken.toWindowContainerToken());
}
change.setMode(info.getTransitMode(target));
change.setStartAbsBounds(info.mAbsoluteBounds);
@@ -1634,6 +1641,19 @@
return mainWin.getAttrs().rotationAnimation;
}
+ /** Applies the new configuration and returns {@code true} if there is a display change. */
+ boolean applyDisplayChangeIfNeeded() {
+ boolean changed = false;
+ for (int i = mParticipants.size() - 1; i >= 0; --i) {
+ final WindowContainer<?> wc = mParticipants.valueAt(i);
+ final DisplayContent dc = wc.asDisplayContent();
+ if (dc == null || !mChanges.get(dc).hasChanged(dc)) continue;
+ dc.sendNewConfiguration();
+ changed = true;
+ }
+ return changed;
+ }
+
boolean getLegacyIsReady() {
return isCollecting() && mSyncId >= 0;
}
@@ -1664,7 +1684,9 @@
@interface Flag {}
// Usually "post" change state.
- WindowContainer mParent;
+ WindowContainer mEndParent;
+ // Parent before change state.
+ WindowContainer mStartParent;
// State tracking
boolean mExistenceChanged = false;
@@ -1685,6 +1707,7 @@
mAbsoluteBounds.set(origState.getBounds());
mShowWallpaper = origState.showWallpaper();
mRotation = origState.getWindowConfiguration().getRotation();
+ mStartParent = origState.getParent();
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 4f324f2..846aa3e 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -463,13 +463,12 @@
}
/**
- * Collects the window containers which need to be synced with the changing display (e.g.
- * rotating) to the given transition or the current collecting transition.
+ * Collects the window containers which need to be synced with the changing display area into
+ * the current collecting transition.
*/
- void collectForDisplayAreaChange(@NonNull DisplayArea<?> wc, @Nullable Transition incoming) {
- if (incoming == null) incoming = mCollectingTransition;
- if (incoming == null) return;
- final Transition transition = incoming;
+ void collectForDisplayAreaChange(@NonNull DisplayArea<?> wc) {
+ final Transition transition = mCollectingTransition;
+ if (transition == null || !transition.mParticipants.contains(wc)) return;
// Collect all visible tasks.
wc.forAllLeafTasks(task -> {
if (task.isVisible()) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 25193d0..7979048 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3015,6 +3015,10 @@
final float windowCornerRadius = !inMultiWindowMode()
? getDisplayContent().getWindowCornerRadius()
: 0;
+ if (asActivityRecord() != null
+ && asActivityRecord().isNeedsLetterboxedAnimation()) {
+ asActivityRecord().getLetterboxInnerBounds(mTmpRect);
+ }
AnimationAdapter adapter = new LocalAnimationAdapter(
new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
getDisplayContent().mAppTransition.canSkipFirstFrame(),
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6415918..dce0fbe 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -89,6 +89,7 @@
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
+import static android.view.WindowManager.fixScale;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_CANCEL_AND_REDRAW;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
@@ -1323,15 +1324,10 @@
}, UserHandle.ALL, suspendPackagesFilter, null, null);
// Get persisted window scale setting
- mWindowAnimationScaleSetting = Settings.Global.getFloat(resolver,
- Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting);
- mTransitionAnimationScaleSetting = Settings.Global.getFloat(resolver,
- Settings.Global.TRANSITION_ANIMATION_SCALE,
- context.getResources().getFloat(
- R.dimen.config_appTransitionAnimationDurationScaleDefault));
+ mWindowAnimationScaleSetting = getWindowAnimationScaleSetting();
+ mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting();
- setAnimatorDurationScale(Settings.Global.getFloat(resolver,
- Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting));
+ setAnimatorDurationScale(getAnimatorDurationScaleSetting());
mForceDesktopModeOnExternalDisplays = Settings.Global.getInt(resolver,
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0;
@@ -1405,6 +1401,22 @@
lightRadius);
}
+ private float getTransitionAnimationScaleSetting() {
+ return fixScale(Settings.Global.getFloat(mContext.getContentResolver(),
+ Settings.Global.TRANSITION_ANIMATION_SCALE, mContext.getResources().getFloat(
+ R.dimen.config_appTransitionAnimationDurationScaleDefault)));
+ }
+
+ private float getAnimatorDurationScaleSetting() {
+ return fixScale(Settings.Global.getFloat(mContext.getContentResolver(),
+ Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting));
+ }
+
+ private float getWindowAnimationScaleSetting() {
+ return fixScale(Settings.Global.getFloat(mContext.getContentResolver(),
+ Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting));
+ }
+
/**
* Called after all entities (such as the {@link ActivityManagerService}) have been set up and
* associated with the {@link WindowManagerService}.
@@ -3411,11 +3423,6 @@
}
}
- static float fixScale(float scale) {
- if (scale < 0) scale = 0;
- else if (scale > 20) scale = 20;
- return Math.abs(scale);
- }
@Override
public void setAnimationScale(int which, float scale) {
@@ -5340,24 +5347,16 @@
final int mode = msg.arg1;
switch (mode) {
case WINDOW_ANIMATION_SCALE: {
- mWindowAnimationScaleSetting = Settings.Global.getFloat(
- mContext.getContentResolver(),
- Settings.Global.WINDOW_ANIMATION_SCALE,
- mWindowAnimationScaleSetting);
+ mWindowAnimationScaleSetting = getWindowAnimationScaleSetting();
break;
}
case TRANSITION_ANIMATION_SCALE: {
- mTransitionAnimationScaleSetting = Settings.Global.getFloat(
- mContext.getContentResolver(),
- Settings.Global.TRANSITION_ANIMATION_SCALE,
- mTransitionAnimationScaleSetting);
+ mTransitionAnimationScaleSetting =
+ getTransitionAnimationScaleSetting();
break;
}
case ANIMATION_DURATION_SCALE: {
- mAnimatorDurationScaleSetting = Settings.Global.getFloat(
- mContext.getContentResolver(),
- Settings.Global.ANIMATOR_DURATION_SCALE,
- mAnimatorDurationScaleSetting);
+ mAnimatorDurationScaleSetting = getAnimatorDurationScaleSetting();
dispatchNewAnimatorScaleLocked(null);
break;
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 3b9cd36..4f03264 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -397,17 +397,8 @@
mService.deferWindowLayout();
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
try {
- if (transition != null) {
- // First check if we have a display rotation transition and if so, update it.
- final DisplayContent dc = DisplayRotation.getDisplayFromTransition(transition);
- if (dc != null && transition.mChanges.get(dc).hasChanged(dc)) {
- // Go through all tasks and collect them before the rotation
- // TODO(shell-transitions): move collect() to onConfigurationChange once
- // wallpaper handling is synchronized.
- dc.mTransitionController.collectForDisplayAreaChange(dc, transition);
- dc.sendNewConfiguration();
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
- }
+ if (transition != null && transition.applyDisplayChangeIfNeeded()) {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
}
final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
final int hopSize = hops.size();
@@ -428,15 +419,6 @@
addToSyncSet(syncId, wc);
}
if (transition != null) transition.collect(wc);
- final DisplayArea da = wc.asDisplayArea();
- // Only check DisplayArea here as a similar thing is done for DisplayContent above.
- if (da != null && wc.asDisplayContent() == null
- && entry.getValue().getWindowingMode() != da.getWindowingMode()) {
- // Go through all tasks and collect them before changing the windowing mode of a
- // display-level container.
- // TODO(shell-transitions): handle this more elegantly.
- da.mTransitionController.collectForDisplayAreaChange(da, transition);
- }
if ((entry.getValue().getChangeMask()
& WindowContainerTransaction.Change.CHANGE_FORCE_NO_PIP) != 0) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 87b0c8b..202fe55 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -25,6 +25,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.server.am.ProcessList.INVALID_ADJ;
import static com.android.server.wm.ActivityRecord.State.DESTROYED;
import static com.android.server.wm.ActivityRecord.State.DESTROYING;
import static com.android.server.wm.ActivityRecord.State.PAUSED;
@@ -123,6 +124,8 @@
private volatile int mCurProcState = PROCESS_STATE_NONEXISTENT;
// Last reported process state;
private volatile int mRepProcState = PROCESS_STATE_NONEXISTENT;
+ // Currently computed oom adj score
+ private volatile int mCurAdj = INVALID_ADJ;
// are we in the process of crashing?
private volatile boolean mCrashing;
// does the app have a not responding dialog?
@@ -317,6 +320,14 @@
return mCurProcState;
}
+ public void setCurrentAdj(int curAdj) {
+ mCurAdj = curAdj;
+ }
+
+ int getCurrentAdj() {
+ return mCurAdj;
+ }
+
/**
* Sets the computed process state from the oom adjustment calculation. This is frequently
* called in activity manager's lock, so don't use window manager lock here.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 41bcbf6..2432afb 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3803,6 +3803,10 @@
return wpc != null && wpc.registeredForDisplayAreaConfigChanges();
}
+ WindowProcessController getProcess() {
+ return mWpcForDisplayAreaConfigChanges;
+ }
+
/**
* Fills the given window frames and merged configuration for the client.
*
@@ -6049,7 +6053,7 @@
}
boolean hasWallpaperForLetterboxBackground() {
- return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox();
+ return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroundForLetterbox();
}
/**
diff --git a/services/core/xsd/display-device-config/autobrightness.xsd b/services/core/xsd/display-device-config/autobrightness.xsd
new file mode 100644
index 0000000..477625a
--- /dev/null
+++ b/services/core/xsd/display-device-config/autobrightness.xsd
@@ -0,0 +1,33 @@
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<xs:schema version="2.0"
+ elementFormDefault="qualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:complexType name="autoBrightness">
+ <xs:sequence>
+ <!-- Sets the debounce for autoBrightness brightening in millis-->
+ <xs:element name="brighteningLightDebounceMillis" type="xs:nonNegativeInteger"
+ minOccurs="0" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+ <!-- Sets the debounce for autoBrightness darkening in millis-->
+ <xs:element name="darkeningLightDebounceMillis" type="xs:nonNegativeInteger"
+ minOccurs="0" maxOccurs="1">
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 073b131c..bea5e2c 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -23,6 +23,7 @@
<xs:schema version="2.0"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:include schemaLocation="autobrightness.xsd" />
<xs:element name="displayConfiguration">
<xs:complexType>
<xs:sequence>
@@ -102,22 +103,6 @@
</xs:element>
<!-- Type definitions -->
-
- <xs:complexType name="autoBrightness">
- <xs:sequence>
- <!-- Sets the debounce for autoBrightness brightening in millis-->
- <xs:element name="brighteningLightDebounceMillis" type="xs:nonNegativeInteger"
- minOccurs="0" maxOccurs="1">
- <xs:annotation name="final"/>
- </xs:element>
- <!-- Sets the debounce for autoBrightness darkening in millis-->
- <xs:element name="darkeningLightDebounceMillis" type="xs:nonNegativeInteger"
- minOccurs="0" maxOccurs="1">
- <xs:annotation name="final"/>
- </xs:element>
- </xs:sequence>
- </xs:complexType>
-
<xs:complexType name="displayQuirks">
<xs:sequence>
<xs:element name="quirk" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index e9f0bd9..8890070 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -19,8 +19,12 @@
import static com.android.server.testutils.TestUtils.strictMock;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import android.annotation.UiContext;
+import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.RemoteException;
@@ -76,7 +80,8 @@
private WindowMagnificationManager mWindowMagnificationManager;
private MockWindowMagnificationConnection mMockConnection;
- private WindowMagnificationGestureHandler mWindowMagnificationGestureHandler;
+ private SpyWindowMagnificationGestureHandler mWindowMagnificationGestureHandler;
+ private WindowMagnificationGestureHandler mMockWindowMagnificationGestureHandler;
@Mock
MagnificationGestureHandler.Callback mMockCallback;
@Mock
@@ -89,9 +94,11 @@
mock(WindowMagnificationManager.Callback.class), mMockTrace,
new MagnificationScaleProvider(mContext));
mMockConnection = new MockWindowMagnificationConnection();
- mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler(
+ mWindowMagnificationGestureHandler = new SpyWindowMagnificationGestureHandler(
mContext, mWindowMagnificationManager, mMockTrace, mMockCallback,
/** detectTripleTap= */true, /** detectShortcutTrigger= */true, DISPLAY_0);
+ mMockWindowMagnificationGestureHandler =
+ mWindowMagnificationGestureHandler.getMockGestureHandler();
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationGestureHandler.setNext(strictMock(EventStreamTransformation.class));
}
@@ -154,6 +161,18 @@
});
}
+ @Test
+ public void testTripleTapAndHold_logSessionDuration() {
+ // perform triple tap on spy gesture handler
+ goFromStateIdleTo(STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD);
+
+ // perform up event on spy gesture handler
+ returnToNormalFrom(STATE_SHOW_MAGNIFIER_TRIPLE_TAP_AND_HOLD);
+
+ verify(mMockWindowMagnificationGestureHandler)
+ .logMagnificationTripleTapAndHoldSession(anyLong());
+ }
+
private void forEachState(IntConsumer action) {
for (int state = FIRST_STATE; state <= LAST_STATE; state++) {
action.accept(state);
@@ -335,4 +354,31 @@
private String stateDump() {
return "\nCurrent state dump:\n" + mWindowMagnificationGestureHandler.mCurrentState;
}
+
+ private static class SpyWindowMagnificationGestureHandler
+ extends WindowMagnificationGestureHandler {
+
+ private final WindowMagnificationGestureHandler mMockWindowMagnificationGestureHandler;
+
+ SpyWindowMagnificationGestureHandler(@UiContext Context context,
+ WindowMagnificationManager windowMagnificationMgr,
+ AccessibilityTraceManager trace,
+ Callback callback,
+ boolean detectTripleTap, boolean detectShortcutTrigger, int displayId) {
+ super(context, windowMagnificationMgr, trace, callback, detectTripleTap,
+ detectShortcutTrigger, displayId);
+ mMockWindowMagnificationGestureHandler = mock(WindowMagnificationGestureHandler.class);
+ }
+
+ WindowMagnificationGestureHandler getMockGestureHandler() {
+ return mMockWindowMagnificationGestureHandler;
+ }
+
+ @Override
+ void logMagnificationTripleTapAndHoldSession(long duration) {
+ super.logMagnificationTripleTapAndHoldSession(duration);
+ mMockWindowMagnificationGestureHandler
+ .logMagnificationTripleTapAndHoldSession(duration);
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index 978000a..25ad2be 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -23,10 +23,12 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
@@ -293,6 +295,17 @@
}
@Test
+ public void logTrackingTypingFocus_processScroll_logDuration() {
+ WindowMagnificationManager spyWindowMagnificationManager = spy(mWindowMagnificationManager);
+ spyWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, 50f, 50f);
+ spyWindowMagnificationManager.onImeWindowVisibilityChanged(TEST_DISPLAY, /* shown */ true);
+
+ spyWindowMagnificationManager.processScroll(TEST_DISPLAY, 10f, 10f);
+
+ verify(spyWindowMagnificationManager).logTrackingTypingFocus(anyLong());
+ }
+
+ @Test
public void onRectangleOnScreenRequested_trackingDisabledByOnDrag_withoutMovingMagnifier()
throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index e2c3a94..4c939f0 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -83,6 +83,7 @@
VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED,
/* activityListener= */ null,
/* activityBlockedCallback= */ null,
+ /* secureWindowCallback= */ null,
/* deviceProfile= */ DEVICE_PROFILE_APP_STREAMING);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 911fb6a..08c2c6e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -1301,6 +1301,21 @@
}
@Test
+ public void testA11yCrossUserEventNotSent() throws Exception {
+ final Notification n = new Builder(getContext(), "test")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
+ int userId = mUser.getIdentifier() + 1;
+ StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
+ mPid, n, UserHandle.of(userId), null, System.currentTimeMillis());
+ NotificationRecord r = new NotificationRecord(getContext(), sbn,
+ new NotificationChannel("test", "test", IMPORTANCE_HIGH));
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verify(mAccessibilityService, never()).sendAccessibilityEvent(any(), anyInt());
+ }
+
+ @Test
public void testLightsScreenOn() {
mService.mScreenOn = true;
NotificationRecord r = getLightsNotification();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 443ed58..d78ca1b 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -150,6 +150,7 @@
import android.graphics.Color;
import android.graphics.drawable.Icon;
import android.media.AudioManager;
+import android.media.IRingtonePlayer;
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.Binder;
@@ -4238,6 +4239,59 @@
}
@Test
+ public void testSubstituteAppName_hasPermission() throws RemoteException {
+ String subName = "Substitute Name";
+ when(mPackageManager.checkPermission(
+ eq(android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME), any(), anyInt()))
+ .thenReturn(PERMISSION_GRANTED);
+ Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName);
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .addExtras(extras);
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+ "testSubstituteAppNamePermission", mUid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ NotificationRecord posted = mService.findNotificationLocked(
+ PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+
+ assertTrue(posted.getNotification().extras
+ .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
+ assertEquals(posted.getNotification().extras
+ .getString(Notification.EXTRA_SUBSTITUTE_APP_NAME), subName);
+ }
+
+ @Test
+ public void testSubstituteAppName_noPermission() throws RemoteException {
+ when(mPackageManager.checkPermission(
+ eq(android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME), any(), anyInt()))
+ .thenReturn(PERMISSION_DENIED);
+ Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Substitute Name");
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .addExtras(extras);
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+ "testSubstituteAppNamePermission", mUid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+ NotificationRecord posted = mService.findNotificationLocked(
+ PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+
+ assertFalse(posted.getNotification().extras
+ .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
+ }
+
+ @Test
public void testGetNotificationCountLocked() {
String sampleTagToExclude = null;
int sampleIdToExclude = 0;
@@ -7738,6 +7792,34 @@
}
@Test
+ public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped()
+ throws RemoteException {
+ IRingtonePlayer mockPlayer = mock(IRingtonePlayer.class);
+ when(mAudioManager.getRingtonePlayer()).thenReturn(mockPlayer);
+ // Set up volume to be above 0 for the sound to actually play
+ when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
+
+ setUpPrefsForBubbles(PKG, mUid,
+ true /* global */,
+ BUBBLE_PREFERENCE_ALL /* app */,
+ true /* channel */);
+
+ // Post a bubble notification
+ NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ // Test: suppress notification via bubble metadata update
+ mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(),
+ Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
+ waitForIdle();
+
+ // Check audio is stopped
+ verify(mockPlayer).stopAsync();
+ }
+
+ @Test
public void testGrantInlineReplyUriPermission_recordExists() throws Exception {
int userId = UserManager.isHeadlessSystemUserMode()
? UserHandle.getUserId(UID_HEADLESS)
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 598a22b..d62ac99 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -93,6 +93,7 @@
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
+import android.os.Parcel;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -2447,6 +2448,35 @@
}
@Test
+ public void testGetNotificationChannelGroup() throws Exception {
+ NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted");
+ NotificationChannel base =
+ new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT);
+ base.setGroup("not");
+ NotificationChannel convo =
+ new NotificationChannel("convo", "belongs to notDeleted", IMPORTANCE_DEFAULT);
+ convo.setGroup("not");
+ convo.setConversationId("not deleted", "banana");
+
+ mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, base, true, false);
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, convo, true, false);
+ mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true);
+
+ NotificationChannelGroup g
+ = mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1);
+ Parcel parcel = Parcel.obtain();
+ g.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannelGroup g2
+ = mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1);
+ Parcel parcel2 = Parcel.obtain();
+ g2.writeToParcel(parcel2, 0);
+ parcel2.setDataPosition(0);
+ }
+
+ @Test
public void testOnUserRemoved() throws Exception {
int[] user0Uids = {98, 235, 16, 3782};
int[] user1Uids = new int[user0Uids.length];
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 7415460..f61effa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -474,7 +474,7 @@
}
@Test
- public void testActivityRecordReparentToTaskFragment() {
+ public void testActivityRecordReparentedToTaskFragment() {
final ActivityRecord activity = createActivityRecord(mDc);
final SurfaceControl activityLeash = mock(SurfaceControl.class);
doNothing().when(activity).setDropInputMode(anyInt());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 600881e..be266c9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1904,10 +1904,10 @@
testPlayer.start();
assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation());
assertNotNull(testPlayer.mLastReady);
- assertEquals(dc, DisplayRotation.getDisplayFromTransition(testPlayer.mLastTransit));
WindowContainerToken dcToken = dc.mRemoteToken.toWindowContainerToken();
assertNotEquals(testPlayer.mLastReady.getChange(dcToken).getEndRotation(),
testPlayer.mLastReady.getChange(dcToken).getStartRotation());
+ assertTrue(testPlayer.mLastTransit.applyDisplayChangeIfNeeded());
testPlayer.finish();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index e502f2f..d400a4c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -56,6 +56,7 @@
private boolean mHasWallpaperBackground = false;
private int mBlurRadius = 0;
private float mDarkScrimAlpha = 0.5f;
+ private SurfaceControl mParentSurface = mock(SurfaceControl.class);
@Before
public void setUp() throws Exception {
@@ -63,7 +64,8 @@
mLetterbox = new Letterbox(mSurfaces, StubTransaction::new,
() -> mAreCornersRounded, () -> Color.valueOf(mColor),
() -> mHasWallpaperBackground, () -> mBlurRadius, () -> mDarkScrimAlpha,
- /* doubleTapCallbackX= */ x -> {}, /* doubleTapCallbackY= */ y -> {});
+ /* doubleTapCallbackX= */ x -> {}, /* doubleTapCallbackY= */ y -> {},
+ () -> mParentSurface);
mTransaction = spy(StubTransaction.class);
}
@@ -205,6 +207,22 @@
}
@Test
+ public void testNeedsApplySurfaceChanges_setParentSurface() {
+ mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+ mLetterbox.applySurfaceChanges(mTransaction);
+
+ verify(mTransaction).reparent(mSurfaces.top, mParentSurface);
+ assertFalse(mLetterbox.needsApplySurfaceChanges());
+
+ mParentSurface = mock(SurfaceControl.class);
+
+ assertTrue(mLetterbox.needsApplySurfaceChanges());
+
+ mLetterbox.applySurfaceChanges(mTransaction);
+ verify(mTransaction).reparent(mSurfaces.top, mParentSurface);
+ }
+
+ @Test
public void testApplySurfaceChanges_cornersNotRounded_surfaceFullWindowSurfaceNotCreated() {
mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
mLetterbox.applySurfaceChanges(mTransaction);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 8b3cff8..da72030 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -158,7 +158,7 @@
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer, never()).onTaskFragmentAppeared(any());
+ verify(mOrganizer, never()).onTaskFragmentAppeared(any(), any());
// Send callback when the TaskFragment is attached.
setupMockParent(mTaskFragment, mTask);
@@ -166,7 +166,7 @@
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentAppeared(any());
+ verify(mOrganizer).onTaskFragmentAppeared(any(), any());
}
@Test
@@ -179,13 +179,13 @@
mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
+ verify(mOrganizer, never()).onTaskFragmentInfoChanged(any(), any());
// Call onTaskFragmentAppeared first.
mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentAppeared(any());
+ verify(mOrganizer).onTaskFragmentAppeared(any(), any());
// No callback if the info is not changed.
doReturn(true).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
@@ -195,7 +195,7 @@
mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
+ verify(mOrganizer, never()).onTaskFragmentInfoChanged(any(), any());
// Trigger callback if the info is changed.
doReturn(false).when(mTaskFragmentInfo).equalsForTaskFragmentOrganizer(any());
@@ -204,7 +204,7 @@
mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentInfoChanged(mTaskFragmentInfo);
+ verify(mOrganizer).onTaskFragmentInfoChanged(any(), eq(mTaskFragmentInfo));
}
@Test
@@ -215,7 +215,7 @@
mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentVanished(any());
+ verify(mOrganizer).onTaskFragmentVanished(any(), any());
}
@Test
@@ -228,10 +228,10 @@
mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer, never()).onTaskFragmentAppeared(any());
- verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
- verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(anyInt(), any());
- verify(mOrganizer).onTaskFragmentVanished(mTaskFragmentInfo);
+ verify(mOrganizer, never()).onTaskFragmentAppeared(any(), any());
+ verify(mOrganizer, never()).onTaskFragmentInfoChanged(any(), any());
+ verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), anyInt(), any());
+ verify(mOrganizer).onTaskFragmentVanished(any(), eq(mTaskFragmentInfo));
// Not trigger onTaskFragmentInfoChanged.
// Call onTaskFragmentAppeared before calling onTaskFragmentInfoChanged.
@@ -244,10 +244,10 @@
mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer, never()).onTaskFragmentAppeared(any());
- verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
- verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(anyInt(), any());
- verify(mOrganizer).onTaskFragmentVanished(mTaskFragmentInfo);
+ verify(mOrganizer, never()).onTaskFragmentAppeared(any(), any());
+ verify(mOrganizer, never()).onTaskFragmentInfoChanged(any(), any());
+ verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), anyInt(), any());
+ verify(mOrganizer).onTaskFragmentVanished(any(), eq(mTaskFragmentInfo));
}
@Test
@@ -260,7 +260,7 @@
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mTask.mTaskId), any());
+ verify(mOrganizer).onTaskFragmentParentInfoChanged(any(), eq(mTask.mTaskId), any());
// No extra callback if the info is not changed.
clearInvocations(mOrganizer);
@@ -269,7 +269,7 @@
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(anyInt(), any());
+ verify(mOrganizer, never()).onTaskFragmentParentInfoChanged(any(), anyInt(), any());
// Trigger callback if the size is changed.
mTask.getConfiguration().smallestScreenWidthDp = 100;
@@ -277,7 +277,7 @@
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mTask.mTaskId), any());
+ verify(mOrganizer).onTaskFragmentParentInfoChanged(any(), eq(mTask.mTaskId), any());
// Trigger callback if the windowing mode is changed.
clearInvocations(mOrganizer);
@@ -286,7 +286,7 @@
mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mTask.mTaskId), any());
+ verify(mOrganizer).onTaskFragmentParentInfoChanged(any(), eq(mTask.mTaskId), any());
}
@Test
@@ -298,11 +298,12 @@
mErrorToken, null /* taskFragment */, -1 /* opType */, exception);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), eq(null), eq(-1), eq(exception));
+ verify(mOrganizer).onTaskFragmentError(any(), eq(mErrorToken), eq(null), eq(-1),
+ eq(exception));
}
@Test
- public void testOnActivityReparentToTask_activityInOrganizerProcess_useActivityToken() {
+ public void testOnActivityReparentedToTask_activityInOrganizerProcess_useActivityToken() {
// Make sure the activity pid/uid is the same as the organizer caller.
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -314,17 +315,18 @@
task.effectiveUid = uid;
// No need to notify organizer if it is not embedded.
- mController.onActivityReparentToTask(activity);
+ mController.onActivityReparentedToTask(activity);
mController.dispatchPendingEvents();
- verify(mOrganizer, never()).onActivityReparentToTask(anyInt(), any(), any());
+ verify(mOrganizer, never()).onActivityReparentedToTask(any(), anyInt(), any(), any());
// Notify organizer if it was embedded before entered Pip.
activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer;
- mController.onActivityReparentToTask(activity);
+ mController.onActivityReparentedToTask(activity);
mController.dispatchPendingEvents();
- verify(mOrganizer).onActivityReparentToTask(task.mTaskId, activity.intent, activity.token);
+ verify(mOrganizer).onActivityReparentedToTask(any(), eq(task.mTaskId), eq(activity.intent),
+ eq(activity.token));
// Notify organizer if there is any embedded in the Task.
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
@@ -335,15 +337,16 @@
DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
activity.reparent(taskFragment, POSITION_TOP);
activity.mLastTaskFragmentOrganizerBeforePip = null;
- mController.onActivityReparentToTask(activity);
+ mController.onActivityReparentedToTask(activity);
mController.dispatchPendingEvents();
verify(mOrganizer, times(2))
- .onActivityReparentToTask(task.mTaskId, activity.intent, activity.token);
+ .onActivityReparentedToTask(any(), eq(task.mTaskId), eq(activity.intent),
+ eq(activity.token));
}
@Test
- public void testOnActivityReparentToTask_activityNotInOrganizerProcess_useTemporaryToken() {
+ public void testOnActivityReparentedToTask_activityNotInOrganizerProcess_useTemporaryToken() {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
@@ -364,11 +367,11 @@
// Notify organizer if it was embedded before entered Pip.
// Create a temporary token since the activity doesn't belong to the same process.
activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer;
- mController.onActivityReparentToTask(activity);
+ mController.onActivityReparentedToTask(activity);
mController.dispatchPendingEvents();
// Allow organizer to reparent activity in other process using the temporary token.
- verify(mOrganizer).onActivityReparentToTask(eq(task.mTaskId), eq(activity.intent),
+ verify(mOrganizer).onActivityReparentedToTask(any(), eq(task.mTaskId), eq(activity.intent),
token.capture());
final IBinder temporaryToken = token.getValue();
assertNotEquals(activity.token, temporaryToken);
@@ -798,7 +801,7 @@
mController.dispatchPendingEvents();
// Verifies that event was not sent
- verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
+ verify(mOrganizer, never()).onTaskFragmentInfoChanged(any(), any());
}
@Test
@@ -824,7 +827,7 @@
mController.dispatchPendingEvents();
// Verifies that event was not sent
- verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
+ verify(mOrganizer, never()).onTaskFragmentInfoChanged(any(), any());
// Mock the task becomes visible, and activity resumed
doReturn(true).when(task).shouldBeVisible(any());
@@ -832,7 +835,7 @@
// Verifies that event is sent.
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentInfoChanged(any());
+ verify(mOrganizer).onTaskFragmentInfoChanged(any(), any());
}
/**
@@ -866,7 +869,7 @@
reset(mOrganizer);
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentInfoChanged(any());
+ verify(mOrganizer).onTaskFragmentInfoChanged(any(), any());
}
/**
@@ -884,8 +887,8 @@
.createActivityCount(1)
.build();
final ActivityRecord embeddedActivity = taskFragment.getTopNonFinishingActivity();
- // Add another activity in the Task so that it always contains a non-finishing activitiy.
- final ActivityRecord nonEmbeddedActivity = createActivityRecord(task);
+ // Add another activity in the Task so that it always contains a non-finishing activity.
+ createActivityRecord(task);
assertTrue(task.shouldBeVisible(null));
// Dispatch pending info changed event from creating the activity
@@ -893,21 +896,21 @@
taskFragment.mTaskFragmentAppearedSent = true;
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentInfoChanged(any());
+ verify(mOrganizer).onTaskFragmentInfoChanged(any(), any());
// Verify the info changed callback is not called when the task is invisible
reset(mOrganizer);
doReturn(false).when(task).shouldBeVisible(any());
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer, never()).onTaskFragmentInfoChanged(any());
+ verify(mOrganizer, never()).onTaskFragmentInfoChanged(any(), any());
// Finish the embedded activity, and verify the info changed callback is called because the
// TaskFragment is becoming empty.
embeddedActivity.finishing = true;
mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
mController.dispatchPendingEvents();
- verify(mOrganizer).onTaskFragmentInfoChanged(any());
+ verify(mOrganizer).onTaskFragmentInfoChanged(any(), any());
}
/**
@@ -1017,7 +1020,7 @@
// The pending event will be dispatched on the handler (from requestTraversal).
waitHandlerIdle(mWm.mAnimationHandler);
- verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(),
+ verify(mOrganizer).onTaskFragmentError(any(), eq(mErrorToken), any(),
eq(HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT),
any(SecurityException.class));
}
@@ -1056,7 +1059,7 @@
// The pending event will be dispatched on the handler (from requestTraversal).
waitHandlerIdle(mWm.mAnimationHandler);
- verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(),
+ verify(mOrganizer).onTaskFragmentError(any(), eq(mErrorToken), any(),
eq(HIERARCHY_OP_TYPE_REPARENT_CHILDREN), any(SecurityException.class));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 88eadfc..83f1789 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -134,6 +134,23 @@
}
@Test
+ public void testStartChangeTransition_doNotFreezeWhenOnlyMoved() {
+ final Rect startBounds = new Rect(0, 0, 1000, 1000);
+ final Rect endBounds = new Rect(startBounds);
+ endBounds.offset(500, 0);
+ mTaskFragment.setBounds(startBounds);
+ doReturn(true).when(mTaskFragment).isVisible();
+ doReturn(true).when(mTaskFragment).isVisibleRequested();
+
+ clearInvocations(mTransaction);
+ mTaskFragment.setBounds(endBounds);
+
+ // No change transition, but update the organized surface position.
+ verify(mTaskFragment, never()).initializeChangeTransition(any(), any());
+ verify(mTransaction).setPosition(mLeash, endBounds.left, endBounds.top);
+ }
+
+ @Test
public void testNotOkToAnimate_doNotStartChangeTransition() {
mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer);
final Rect startBounds = new Rect(0, 0, 1000, 1000);
@@ -323,7 +340,7 @@
activity.reparent(task, POSITION_TOP);
// Notify the organizer about the reparent.
- verify(mAtm.mTaskFragmentOrganizerController).onActivityReparentToTask(activity);
+ verify(mAtm.mTaskFragmentOrganizerController).onActivityReparentedToTask(activity);
assertNull(activity.mLastTaskFragmentOrganizerBeforePip);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 851be9d..d2cb7ba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -245,7 +245,7 @@
}
@Override
- public void userActivity() {
+ public void userActivity(int displayGroupId, int event) {
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index a1ad07a..0f13fb2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -36,8 +36,10 @@
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static android.window.TransitionInfo.isIndependent;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -1079,6 +1081,39 @@
assertTrue((info.getChanges().get(1).getFlags() & FLAG_IS_EMBEDDED) != 0);
}
+ @Test
+ public void testIncludeEmbeddedActivityReparent() {
+ final Transition transition = createTestTransition(TRANSIT_OPEN);
+ final Task task = createTask(mDisplayContent);
+ task.setBounds(new Rect(0, 0, 2000, 1000));
+ final ActivityRecord activity = createActivityRecord(task);
+ activity.mVisibleRequested = true;
+ // Skip manipulate the SurfaceControl.
+ doNothing().when(activity).setDropInputMode(anyInt());
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ mAtm.mTaskFragmentOrganizerController.registerOrganizer(
+ ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()));
+ final TaskFragment embeddedTf = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setOrganizer(organizer)
+ .build();
+ // TaskFragment with different bounds from Task.
+ embeddedTf.setBounds(new Rect(0, 0, 1000, 1000));
+
+ // Start states.
+ transition.collect(activity);
+ transition.collectExistenceChange(embeddedTf);
+
+ // End states.
+ activity.reparent(embeddedTf, POSITION_TOP);
+
+ // Verify that both activity and TaskFragment are included.
+ final ArrayList<WindowContainer> targets = Transition.calculateTargets(
+ transition.mParticipants, transition.mChanges);
+ assertTrue(targets.contains(embeddedTf));
+ assertTrue(targets.contains(activity));
+ }
+
private static void makeTaskOrganized(Task... tasks) {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
for (Task t : tasks) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 25db81f..bde9c3d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -18,6 +18,8 @@
import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
import static android.Manifest.permission.RECORD_AUDIO;
+import static android.service.attention.AttentionService.PROXIMITY_UNKNOWN;
+import static android.service.voice.HotwordDetectedResult.EXTRA_PROXIMITY_METERS;
import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_EXTERNAL;
import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_MICROPHONE;
import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_SUCCESS;
@@ -56,6 +58,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.attention.AttentionManagerInternal;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.Context;
@@ -182,6 +185,12 @@
final int mUser;
final Context mContext;
+ @Nullable final AttentionManagerInternal mAttentionManagerInternal;
+
+ final AttentionManagerInternal.ProximityUpdateCallbackInternal mProximityCallbackInternal =
+ this::setProximityMeters;
+
+
volatile HotwordDetectionServiceIdentity mIdentity;
private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback;
private Instant mLastRestartInstant;
@@ -202,6 +211,8 @@
private @NonNull ServiceConnection mRemoteHotwordDetectionService;
private IBinder mAudioFlinger;
private boolean mDebugHotwordLogging = false;
+ @GuardedBy("mLock")
+ private double mProximityMeters = PROXIMITY_UNKNOWN;
HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
Identity voiceInteractorIdentity, ComponentName serviceName, int userId,
@@ -229,6 +240,10 @@
mServiceConnectionFactory = new ServiceConnectionFactory(intent, bindInstantServiceAllowed);
mRemoteHotwordDetectionService = mServiceConnectionFactory.createLocked();
+ mAttentionManagerInternal = LocalServices.getService(AttentionManagerInternal.class);
+ if (mAttentionManagerInternal != null) {
+ mAttentionManagerInternal.onStartProximityUpdates(mProximityCallbackInternal);
+ }
mLastRestartInstant = Instant.now();
updateStateAfterProcessStart(options, sharedMemory);
@@ -393,6 +408,9 @@
if (mAudioFlinger != null) {
mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0);
}
+ if (mAttentionManagerInternal != null) {
+ mAttentionManagerInternal.onStopProximityUpdates(mProximityCallbackInternal);
+ }
}
void updateStateLocked(PersistableBundle options, SharedMemory sharedMemory) {
@@ -460,6 +478,7 @@
mSoftwareCallback.onError();
return;
}
+ saveProximityMetersToBundle(result);
mSoftwareCallback.onDetected(result, null, null);
if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
@@ -564,6 +583,7 @@
externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION);
return;
}
+ saveProximityMetersToBundle(result);
externalCallback.onKeyphraseDetected(recognitionEvent, result);
if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
@@ -643,6 +663,7 @@
externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION);
return;
}
+ saveProximityMetersToBundle(result);
externalCallback.onKeyphraseDetected(recognitionEvent, result);
if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
@@ -1191,6 +1212,20 @@
});
}
+ private void saveProximityMetersToBundle(HotwordDetectedResult result) {
+ synchronized (mLock) {
+ if (result != null && mProximityMeters != PROXIMITY_UNKNOWN) {
+ result.getExtras().putDouble(EXTRA_PROXIMITY_METERS, mProximityMeters);
+ }
+ }
+ }
+
+ private void setProximityMeters(double proximityMeters) {
+ synchronized (mLock) {
+ mProximityMeters = proximityMeters;
+ }
+ }
+
private static void bestEffortClose(Closeable... closeables) {
for (Closeable closeable : closeables) {
bestEffortClose(closeable);