diff options
429 files changed, 9476 insertions, 2752 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt index da5b88bbfbf4..19de1a5b0aa6 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3349,12 +3349,17 @@ package android.window { 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/Activity.java b/core/java/android/app/Activity.java index 4ea0c32d3b36..7c1f9c80eec1 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -980,7 +980,8 @@ public class Activity extends ContextThemeWrapper boolean mEnterAnimationComplete; private boolean mIsInMultiWindowMode; - private boolean mIsInPictureInPictureMode; + /** @hide */ + boolean mIsInPictureInPictureMode; private boolean mShouldDockBigOverlays; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f384fa9e6a0b..a70a1a8d51de 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4162,7 +4162,8 @@ public final class ActivityThread extends ClientTransactionHandler private void schedulePauseWithUserLeavingHint(ActivityClientRecord r) { final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token); transaction.setLifecycleStateRequest(PauseActivityItem.obtain(r.activity.isFinishing(), - /* userLeaving */ true, r.activity.mConfigChangeFlags, /* dontReport */ false)); + /* userLeaving */ true, r.activity.mConfigChangeFlags, /* dontReport */ false, + /* autoEnteringPip */ false)); executeTransaction(transaction); } @@ -4952,12 +4953,18 @@ public final class ActivityThread extends ClientTransactionHandler @Override public void handlePauseActivity(ActivityClientRecord r, boolean finished, boolean userLeaving, - int configChanges, PendingTransactionActions pendingActions, String reason) { + int configChanges, boolean autoEnteringPip, PendingTransactionActions pendingActions, + String reason) { if (userLeaving) { performUserLeavingActivity(r); } r.activity.mConfigChangeFlags |= configChanges; + if (autoEnteringPip) { + // Set mIsInPictureInPictureMode earlier in case of auto-enter-pip, see also + // {@link Activity#enterPictureInPictureMode(PictureInPictureParams)}. + r.activity.mIsInPictureInPictureMode = true; + } performPauseActivity(r, finished, reason, pendingActions); // Make sure any pending writes are now committed. diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index cb64173b7809..692d3f3eea9a 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1906,6 +1906,7 @@ public class AppOpsManager { OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER, OP_SCHEDULE_EXACT_ALARM, OP_MANAGE_MEDIA, + OP_GET_USAGE_STATS, }; /** diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 65e6ab7a2137..a7566fdaae64 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -97,8 +97,8 @@ public abstract class ClientTransactionHandler { /** Pause the activity. */ public abstract void handlePauseActivity(@NonNull ActivityClientRecord r, boolean finished, - boolean userLeaving, int configChanges, PendingTransactionActions pendingActions, - String reason); + boolean userLeaving, int configChanges, boolean autoEnteringPip, + PendingTransactionActions pendingActions, String reason); /** * Resume the activity. diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index c9cc1a179102..05c9fca5ed68 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -124,8 +124,13 @@ public final class NotificationChannel implements Parcelable { /** * 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 @@ public final class NotificationChannel implements Parcelable { */ 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 @@ public final class NotificationChannel implements Parcelable { 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 @@ public final class NotificationChannel implements Parcelable { 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 f97415ca20c8..807bd5764cba 100644 --- a/core/java/android/app/NotificationChannelGroup.java +++ b/core/java/android/app/NotificationChannelGroup.java @@ -20,6 +20,7 @@ import android.annotation.SystemApi; 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 @@ public final class NotificationChannelGroup implements Parcelable { /** * 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 @@ public final class NotificationChannelGroup implements Parcelable { 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 @@ public final class NotificationChannelGroup implements Parcelable { */ 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 @@ public final class NotificationChannelGroup implements Parcelable { } 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 @@ public final class NotificationChannelGroup implements Parcelable { * 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 @@ public final class NotificationChannelGroup implements Parcelable { /** * @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 @@ public final class NotificationChannelGroup implements Parcelable { 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/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java index 813e0f93a1f7..965e761ebfb3 100644 --- a/core/java/android/app/servertransaction/PauseActivityItem.java +++ b/core/java/android/app/servertransaction/PauseActivityItem.java @@ -39,13 +39,14 @@ public class PauseActivityItem extends ActivityLifecycleItem { private boolean mUserLeaving; private int mConfigChanges; private boolean mDontReport; + private boolean mAutoEnteringPip; @Override public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); - client.handlePauseActivity(r, mFinished, mUserLeaving, mConfigChanges, pendingActions, - "PAUSE_ACTIVITY_ITEM"); + client.handlePauseActivity(r, mFinished, mUserLeaving, mConfigChanges, mAutoEnteringPip, + pendingActions, "PAUSE_ACTIVITY_ITEM"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -71,7 +72,7 @@ public class PauseActivityItem extends ActivityLifecycleItem { /** Obtain an instance initialized with provided params. */ public static PauseActivityItem obtain(boolean finished, boolean userLeaving, int configChanges, - boolean dontReport) { + boolean dontReport, boolean autoEnteringPip) { PauseActivityItem instance = ObjectPool.obtain(PauseActivityItem.class); if (instance == null) { instance = new PauseActivityItem(); @@ -80,6 +81,7 @@ public class PauseActivityItem extends ActivityLifecycleItem { instance.mUserLeaving = userLeaving; instance.mConfigChanges = configChanges; instance.mDontReport = dontReport; + instance.mAutoEnteringPip = autoEnteringPip; return instance; } @@ -94,6 +96,7 @@ public class PauseActivityItem extends ActivityLifecycleItem { instance.mUserLeaving = false; instance.mConfigChanges = 0; instance.mDontReport = true; + instance.mAutoEnteringPip = false; return instance; } @@ -105,6 +108,7 @@ public class PauseActivityItem extends ActivityLifecycleItem { mUserLeaving = false; mConfigChanges = 0; mDontReport = false; + mAutoEnteringPip = false; ObjectPool.recycle(this); } @@ -117,6 +121,7 @@ public class PauseActivityItem extends ActivityLifecycleItem { dest.writeBoolean(mUserLeaving); dest.writeInt(mConfigChanges); dest.writeBoolean(mDontReport); + dest.writeBoolean(mAutoEnteringPip); } /** Read from Parcel. */ @@ -125,6 +130,7 @@ public class PauseActivityItem extends ActivityLifecycleItem { mUserLeaving = in.readBoolean(); mConfigChanges = in.readInt(); mDontReport = in.readBoolean(); + mAutoEnteringPip = in.readBoolean(); } public static final @NonNull Creator<PauseActivityItem> CREATOR = @@ -148,7 +154,8 @@ public class PauseActivityItem extends ActivityLifecycleItem { } final PauseActivityItem other = (PauseActivityItem) o; return mFinished == other.mFinished && mUserLeaving == other.mUserLeaving - && mConfigChanges == other.mConfigChanges && mDontReport == other.mDontReport; + && mConfigChanges == other.mConfigChanges && mDontReport == other.mDontReport + && mAutoEnteringPip == other.mAutoEnteringPip; } @Override @@ -158,12 +165,14 @@ public class PauseActivityItem extends ActivityLifecycleItem { result = 31 * result + (mUserLeaving ? 1 : 0); result = 31 * result + mConfigChanges; result = 31 * result + (mDontReport ? 1 : 0); + result = 31 * result + (mAutoEnteringPip ? 1 : 0); return result; } @Override public String toString() { return "PauseActivityItem{finished=" + mFinished + ",userLeaving=" + mUserLeaving - + ",configChanges=" + mConfigChanges + ",dontReport=" + mDontReport + "}"; + + ",configChanges=" + mConfigChanges + ",dontReport=" + mDontReport + + ",autoEnteringPip=" + mAutoEnteringPip + "}"; } } diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index 25ff8a78a0c8..de1d38a64163 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -227,7 +227,8 @@ public class TransactionExecutor { break; case ON_PAUSE: mTransactionHandler.handlePauseActivity(r, false /* finished */, - false /* userLeaving */, 0 /* configChanges */, mPendingActions, + false /* userLeaving */, 0 /* configChanges */, + false /* autoEnteringPip */, mPendingActions, "LIFECYCLER_PAUSE_ACTIVITY"); break; case ON_STOP: diff --git a/core/java/android/attention/AttentionManagerInternal.java b/core/java/android/attention/AttentionManagerInternal.java index 47bec618cfd9..24fe0dbe5760 100644 --- a/core/java/android/attention/AttentionManagerInternal.java +++ b/core/java/android/attention/AttentionManagerInternal.java @@ -83,11 +83,11 @@ public abstract class AttentionManagerInternal { } /** 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 a9d665c8b8a5..621eab558337 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -1963,7 +1963,6 @@ public class SoundTrigger { } 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 @@ public class SoundTrigger { 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 06c35b5bec5d..801d34d9d884 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -956,16 +956,7 @@ public abstract class BatteryStats implements Parcelable { 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 @@ public abstract class BatteryStats implements Parcelable { } 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 13ca2c34b27e..8a203e07ae6d 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -345,6 +345,44 @@ public final class PowerManager { 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 d6566048f2c4..b2f7c60fe3b6 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1971,7 +1971,8 @@ public class UserManager { /** @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 a76524a10ddb..592673ef90ea 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10591,6 +10591,13 @@ public final class Settings { 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 72341453a1f4..ab71459ed51e 100644 --- a/core/java/android/service/voice/HotwordDetectedResult.java +++ b/core/java/android/service/voice/HotwordDetectedResult.java @@ -95,6 +95,16 @@ public final class HotwordDetectedResult implements Parcelable { /** 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 @@ public final class HotwordDetectedResult implements Parcelable { * <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 @@ public final class HotwordDetectedResult implements Parcelable { "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 @@ public final class HotwordDetectedResult implements Parcelable { * <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 @@ public final class HotwordDetectedResult implements Parcelable { * <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 @@ public final class HotwordDetectedResult implements Parcelable { } @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 a2cb1d5c6bd2..0e3bcd1b6842 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -314,6 +314,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation (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 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation 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 class InsetsController implements WindowInsetsController, InsetsAnimation 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 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation 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 class InsetsController implements WindowInsetsController, InsetsAnimation 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 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } if (DEBUG) Log.d(TAG, "InternalAnimationControlListener onCancelled types:" + mRequestedTypes); + if (mLoggingListener != null) { + mLoggingListener.onCancelled(controller); + } } protected Interpolator getInsetsInterpolator() { @@ -1147,6 +1161,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation 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 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation 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 c61baf6fb40c..3fe9110283a6 100644 --- a/core/java/android/view/PendingInsetsController.java +++ b/core/java/android/view/PendingInsetsController.java @@ -44,6 +44,7 @@ public class PendingInsetsController implements WindowInsetsController { private ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners = new ArrayList<>(); private int mCaptionInsetsHeight = 0; + private WindowInsetsAnimationControlListener mLoggingListener; @Override public void show(int types) { @@ -176,6 +177,9 @@ public class PendingInsetsController implements WindowInsetsController { 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 @@ public class PendingInsetsController implements WindowInsetsController { mAppearance = 0; mAppearanceMask = 0; mAnimationsDisabled = false; - + mLoggingListener = null; // After replaying, we forward everything directly to the replayed instance. mReplayedInsetsController = controller; } @@ -198,6 +202,16 @@ public class PendingInsetsController implements WindowInsetsController { } @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 5721fa6dd11a..3acb0534e388 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -28,8 +28,8 @@ import android.os.Parcel; 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 @@ public class SurfaceControlViewHost { /** @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 af57f3ba215f..ec6b4acd6aff 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -905,17 +905,11 @@ public final class ViewRootImpl implements ViewParent, 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 @@ public final class ViewRootImpl implements ViewParent, 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 227b9f402bba..63f9e13214ff 100644 --- a/core/java/android/view/WindowInsetsController.java +++ b/core/java/android/view/WindowInsetsController.java @@ -201,6 +201,21 @@ public interface WindowInsetsController { @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 67352c02ce18..2195b83933a5 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1023,6 +1023,14 @@ public interface WindowManager extends ViewManager { } } + /** + * 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 cae48683810e..b5a742bfb2eb 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -89,6 +89,7 @@ import android.view.InputEventSender; 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 @@ public final class InputMethodManager { 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/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl index 8407d10bc3ea..884ca77ea377 100644 --- a/core/java/android/window/ITaskFragmentOrganizerController.aidl +++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl @@ -16,8 +16,10 @@ package android.window; +import android.os.IBinder; import android.view.RemoteAnimationDefinition; import android.window.ITaskFragmentOrganizer; +import android.window.WindowContainerTransaction; /** @hide */ interface ITaskFragmentOrganizerController { @@ -46,8 +48,15 @@ interface ITaskFragmentOrganizerController { void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer, int taskId); /** - * Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and - * only occupies a portion of Task bounds. - */ + * Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and + * only occupies a portion of Task bounds. + */ boolean isActivityEmbedded(in IBinder activityToken); + + /** + * Notifies the server that the organizer has finished handling the given transaction. The + * server should apply the given {@link WindowContainerTransaction} for the necessary changes. + */ + void onTransactionHandled(in ITaskFragmentOrganizer organizer, in IBinder transactionToken, + in WindowContainerTransaction wct); } diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java index 5372071f7f0e..7b6139fbcc2f 100644 --- a/core/java/android/window/TaskFragmentOrganizer.java +++ b/core/java/android/window/TaskFragmentOrganizer.java @@ -148,27 +148,97 @@ public class TaskFragmentOrganizer extends WindowOrganizer { } /** + * Notifies the server that the organizer has finished handling the given transaction. The + * server should apply the given {@link WindowContainerTransaction} for the necessary changes. + * + * @param transactionToken {@link TaskFragmentTransaction#getTransactionToken()} from + * {@link #onTransactionReady(TaskFragmentTransaction)} + * @param wct {@link WindowContainerTransaction} that the server should apply for + * update of the transaction. + * @see com.android.server.wm.WindowOrganizerController#enforceTaskPermission for permission + * requirement. + * @hide + */ + public void onTransactionHandled(@NonNull IBinder transactionToken, + @NonNull WindowContainerTransaction wct) { + wct.setTaskFragmentOrganizer(mInterface); + try { + getController().onTransactionHandled(mInterface, transactionToken, wct); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * 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 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 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. @@ -176,7 +246,13 @@ public class TaskFragmentOrganizer extends WindowOrganizer { * 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) {} @@ -189,11 +265,13 @@ public class TaskFragmentOrganizer extends WindowOrganizer { * Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override * bounds. * + * @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. - * @hide */ - 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()) { @@ -211,9 +289,8 @@ public class TaskFragmentOrganizer extends WindowOrganizer { * @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( @@ -223,6 +300,8 @@ public class TaskFragmentOrganizer extends WindowOrganizer { * 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 @@ -231,7 +310,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer { * 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. @@ -244,6 +323,8 @@ public class TaskFragmentOrganizer extends WindowOrganizer { * 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 @@ -251,10 +332,9 @@ public class TaskFragmentOrganizer extends WindowOrganizer { * 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 onActivityReparentedToTask(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 @@ -262,9 +342,9 @@ public class TaskFragmentOrganizer extends WindowOrganizer { * @hide */ 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: @@ -277,10 +357,10 @@ public class TaskFragmentOrganizer extends WindowOrganizer { 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 @@ -294,18 +374,19 @@ public class TaskFragmentOrganizer extends WindowOrganizer { } } - 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), @@ -315,6 +396,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer { break; case TYPE_ACTIVITY_REPARENTED_TO_TASK: onActivityReparentedToTask( + wct, change.getTaskId(), change.getActivityIntent(), change.getActivityToken()); @@ -324,6 +406,9 @@ public class TaskFragmentOrganizer extends WindowOrganizer { "Unknown TaskFragmentEvent=" + change.getType()); } } + + // Notify the server, and the server should apply the WindowContainerTransaction. + onTransactionHandled(transaction.getTransactionToken(), wct); } @Override diff --git a/core/java/android/window/TaskFragmentTransaction.java b/core/java/android/window/TaskFragmentTransaction.java index 07e8e8c473c6..84a5fea9f57f 100644 --- a/core/java/android/window/TaskFragmentTransaction.java +++ b/core/java/android/window/TaskFragmentTransaction.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; import android.content.res.Configuration; +import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; @@ -41,19 +42,31 @@ import java.util.List; */ public final class TaskFragmentTransaction implements Parcelable { + /** Unique token to represent this transaction. */ + private final IBinder mTransactionToken; + + /** Changes in this transaction. */ private final ArrayList<Change> mChanges = new ArrayList<>(); - public TaskFragmentTransaction() {} + public TaskFragmentTransaction() { + mTransactionToken = new Binder(); + } private TaskFragmentTransaction(Parcel in) { + mTransactionToken = in.readStrongBinder(); in.readTypedList(mChanges, Change.CREATOR); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeStrongBinder(mTransactionToken); dest.writeTypedList(mChanges); } + public IBinder getTransactionToken() { + return mTransactionToken; + } + /** Adds a {@link Change} to this transaction. */ public void addChange(@Nullable Change change) { if (change != null) { @@ -74,7 +87,9 @@ public final class TaskFragmentTransaction implements Parcelable { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("TaskFragmentTransaction{changes=["); + sb.append("TaskFragmentTransaction{token="); + sb.append(mTransactionToken); + sb.append(" changes=["); for (int i = 0; i < mChanges.size(); ++i) { if (i > 0) { sb.append(','); diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 98d4c5976adc..06473b5ee8de 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -6144,7 +6144,8 @@ public class BatteryStatsImpl extends BatteryStats { } @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 @@ public class BatteryStatsImpl extends BatteryStats { } @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 3eae89e350a0..836786d7c592 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 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable 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 90bab47c0304..10fd12054820 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 @@ Copyright (C) 2015 The Android Open Source Project 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 05b9c8a39544..1af80a5e6e6c 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 e9b42d392a2c..78ec14579bf1 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 e3b710063721..17f0fd0b7d02 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 @@ ul.</string> <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 205681c8f59a..c098aca7b377 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 000000000000..2a3da05eabb3 --- /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 000000000000..647bfe84231d --- /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/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index 50639be57f22..942e1cf3eed5 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -223,15 +223,15 @@ public class ObjectPoolTests { @Test public void testRecyclePauseActivityItemItem() { - PauseActivityItem emptyItem = PauseActivityItem.obtain(false, false, 0, false); - PauseActivityItem item = PauseActivityItem.obtain(true, true, 5, true); + PauseActivityItem emptyItem = PauseActivityItem.obtain(false, false, 0, false, false); + PauseActivityItem item = PauseActivityItem.obtain(true, true, 5, true, true); assertNotSame(item, emptyItem); assertFalse(item.equals(emptyItem)); item.recycle(); assertEquals(item, emptyItem); - PauseActivityItem item2 = PauseActivityItem.obtain(true, false, 5, true); + PauseActivityItem item2 = PauseActivityItem.obtain(true, false, 5, true, true); assertSame(item, item2); assertFalse(item2.equals(emptyItem)); } diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index 0eca0a8cb1a7..c868963c4d02 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -235,7 +235,8 @@ public class TransactionParcelTests { public void testPause() { // Write to parcel PauseActivityItem item = PauseActivityItem.obtain(true /* finished */, - true /* userLeaving */, 135 /* configChanges */, true /* dontReport */); + true /* userLeaving */, 135 /* configChanges */, true /* dontReport */, + true /* autoEnteringPip */); writeAndPrepareForReading(item); // Read from parcel and assert diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index ed6a649021a1..6e59b83810e1 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -236,6 +236,21 @@ public class InsetsControllerTest { } @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 03c8b1bcb475..690b35879388 100644 --- a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java @@ -213,6 +213,25 @@ public class PendingInsetsControllerTest { } @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/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index 47f70ddf2d42..ad72d49d2d6d 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -299,8 +299,8 @@ public class ActivityThreadClientTest { private void pauseActivity(ActivityClientRecord r) { mThread.handlePauseActivity(r, false /* finished */, - false /* userLeaving */, 0 /* configChanges */, null /* pendingActions */, - "test"); + false /* userLeaving */, 0 /* configChanges */, false /* autoEnteringPip */, + null /* pendingActions */, "test"); } private void stopActivity(ActivityClientRecord r) { diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index e8873cd4a3e7..4976784416ad 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -2041,6 +2041,12 @@ "group": "WM_DEBUG_CONFIGURATION", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "-108248992": { + "message": "Defer transition ready for TaskFragmentTransaction=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + }, "-106400104": { "message": "Preload recents with %s", "level": "DEBUG", @@ -2089,6 +2095,12 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/TaskFragment.java" }, + "-79016993": { + "message": "Continue transition ready for TaskFragmentTransaction=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + }, "-70719599": { "message": "Unregister remote animations for organizer=%s uid=%d pid=%d", "level": "VERBOSE", diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java index bdf703c9bd38..7e9c4189dabb 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.app.ActivityThread; 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 @@ public class WindowExtensionsImpl implements WindowExtensions { 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 @@ public class WindowExtensionsImpl implements WindowExtensions { } 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 000000000000..3adae7006369 --- /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 9fb7d1988772..1335e5ea051f 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java @@ -271,56 +271,49 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { } @Override - public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) { - final WindowContainerTransaction wct = new WindowContainerTransaction(); + public void onTaskFragmentAppeared(@NonNull WindowContainerTransaction wct, + @NonNull TaskFragmentInfo taskFragmentInfo) { final IBinder fragmentToken = taskFragmentInfo.getFragmentToken(); mFragmentInfos.put(fragmentToken, taskFragmentInfo); mCallback.onTaskFragmentAppeared(wct, taskFragmentInfo); - applyTransaction(wct); } @Override - public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) { - final WindowContainerTransaction wct = new WindowContainerTransaction(); + public void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct, + @NonNull TaskFragmentInfo taskFragmentInfo) { final IBinder fragmentToken = taskFragmentInfo.getFragmentToken(); mFragmentInfos.put(fragmentToken, taskFragmentInfo); mCallback.onTaskFragmentInfoChanged(wct, taskFragmentInfo); - applyTransaction(wct); } @Override - public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) { - final WindowContainerTransaction wct = new WindowContainerTransaction(); + public void onTaskFragmentVanished(@NonNull WindowContainerTransaction wct, + @NonNull TaskFragmentInfo taskFragmentInfo) { mFragmentInfos.remove(taskFragmentInfo.getFragmentToken()); mCallback.onTaskFragmentVanished(wct, taskFragmentInfo); - applyTransaction(wct); } @Override - public void onTaskFragmentParentInfoChanged(int taskId, @NonNull Configuration parentConfig) { - final WindowContainerTransaction wct = new WindowContainerTransaction(); + public void onTaskFragmentParentInfoChanged(@NonNull WindowContainerTransaction wct, + int taskId, @NonNull Configuration parentConfig) { mCallback.onTaskFragmentParentInfoChanged(wct, taskId, parentConfig); - applyTransaction(wct); } @Override - public void onActivityReparentedToTask(int taskId, @NonNull Intent activityIntent, - @NonNull IBinder activityToken) { - final WindowContainerTransaction wct = new WindowContainerTransaction(); + public void onActivityReparentedToTask(@NonNull WindowContainerTransaction wct, + int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken) { mCallback.onActivityReparentedToTask(wct, taskId, activityIntent, activityToken); - applyTransaction(wct); } @Override - public void onTaskFragmentError(@NonNull IBinder errorCallbackToken, + public void onTaskFragmentError(@NonNull WindowContainerTransaction wct, + @NonNull IBinder errorCallbackToken, @Nullable TaskFragmentInfo taskFragmentInfo, int opType, @NonNull Throwable exception) { - final WindowContainerTransaction wct = new WindowContainerTransaction(); if (taskFragmentInfo != null) { final IBinder fragmentToken = taskFragmentInfo.getFragmentToken(); mFragmentInfos.put(fragmentToken, taskFragmentInfo); } mCallback.onTaskFragmentError(wct, taskFragmentInfo, opType); - applyTransaction(wct); } } 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 45e2cbe07a56..97d42391b6c4 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.graphics.Rect; 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,10 +69,7 @@ class TaskFragmentAnimationSpec { // 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)); @@ -223,6 +221,12 @@ class TaskFragmentAnimationSpec { 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); @@ -230,9 +234,7 @@ class TaskFragmentAnimationSpec { @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/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar Binary files differindex 918e514f4c89..e9a1721fba2a 100644 --- a/libs/WindowManager/Jetpack/window-extensions-release.aar +++ b/libs/WindowManager/Jetpack/window-extensions-release.aar 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 764e650a807c..b085b73d78ce 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 @@ public class RootDisplayAreaOrganizer extends DisplayAreaOrganizer { 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 6ae0f9ba0485..d5d4935f0529 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_MULTI_WINDOW; 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.StartingWindowInfo; 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 @@ public class ShellTaskOrganizer extends TaskOrganizer implements 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 @@ public class ShellTaskOrganizer extends TaskOrganizer implements 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 @@ public class ShellTaskOrganizer extends TaskOrganizer implements 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 d28a68a42b2b..a8764e05c3e2 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 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, /** 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 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, 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 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, 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 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, 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 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, @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 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, }); } + /** 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/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java index 2c02006c8ca5..99b8885acdef 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java @@ -821,7 +821,7 @@ public class Bubble implements BubbleViewProvider { /** * Description of current bubble state. */ - public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { + public void dump(@NonNull PrintWriter pw) { pw.print("key: "); pw.println(mKey); pw.print(" showInShade: "); pw.println(showInShade()); pw.print(" showDot: "); pw.println(showDot()); @@ -831,7 +831,7 @@ public class Bubble implements BubbleViewProvider { pw.print(" suppressNotif: "); pw.println(shouldSuppressNotification()); pw.print(" autoExpand: "); pw.println(shouldAutoExpand()); if (mExpandedView != null) { - mExpandedView.dump(pw, args); + mExpandedView.dump(pw); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index de26b54971ca..dcbb272feab8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -72,7 +72,6 @@ import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.RankingMap; import android.util.Log; import android.util.Pair; -import android.util.Slog; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; @@ -100,6 +99,7 @@ import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.onehanded.OneHandedTransitionCallback; import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.sysui.ConfigurationChangeListener; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; @@ -159,6 +159,7 @@ public class BubbleController implements ConfigurationChangeListener { private final TaskViewTransitions mTaskViewTransitions; private final SyncTransactionQueue mSyncQueue; private final ShellController mShellController; + private final ShellCommandHandler mShellCommandHandler; // Used to post to main UI thread private final ShellExecutor mMainExecutor; @@ -229,6 +230,7 @@ public class BubbleController implements ConfigurationChangeListener { public BubbleController(Context context, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellController shellController, BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer, @@ -252,6 +254,7 @@ public class BubbleController implements ConfigurationChangeListener { TaskViewTransitions taskViewTransitions, SyncTransactionQueue syncQueue) { mContext = context; + mShellCommandHandler = shellCommandHandler; mShellController = shellController; mLauncherApps = launcherApps; mBarService = statusBarService == null @@ -431,6 +434,7 @@ public class BubbleController implements ConfigurationChangeListener { mCurrentProfiles = userProfiles; mShellController.addConfigurationChangeListener(this); + mShellCommandHandler.addDumpCallback(this::dump, this); } @VisibleForTesting @@ -538,7 +542,6 @@ public class BubbleController implements ConfigurationChangeListener { if (mNotifEntryToExpandOnShadeUnlock != null) { expandStackAndSelectBubble(mNotifEntryToExpandOnShadeUnlock); - mNotifEntryToExpandOnShadeUnlock = null; } updateStack(); @@ -925,15 +928,6 @@ public class BubbleController implements ConfigurationChangeListener { return (isSummary && isSuppressedSummary) || isSuppressedBubble; } - private void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback) { - if (mBubbleData.isSummarySuppressed(groupKey)) { - mBubbleData.removeSuppressedSummary(groupKey); - if (callback != null) { - callback.accept(mBubbleData.getSummaryKey(groupKey)); - } - } - } - /** Promote the provided bubble from the overflow view. */ public void promoteBubbleFromOverflow(Bubble bubble) { mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK); @@ -1519,14 +1513,15 @@ public class BubbleController implements ConfigurationChangeListener { /** * Description of current bubble state. */ - private void dump(PrintWriter pw, String[] args) { + private void dump(PrintWriter pw, String prefix) { pw.println("BubbleController state:"); - mBubbleData.dump(pw, args); + mBubbleData.dump(pw); pw.println(); if (mStackView != null) { - mStackView.dump(pw, args); + mStackView.dump(pw); } pw.println(); + mImpl.mCachedState.dump(pw); } /** @@ -1711,28 +1706,12 @@ public class BubbleController implements ConfigurationChangeListener { } @Override - public boolean isStackExpanded() { - return mCachedState.isStackExpanded(); - } - - @Override @Nullable public Bubble getBubbleWithShortcutId(String shortcutId) { return mCachedState.getBubbleWithShortcutId(shortcutId); } @Override - public void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback, - Executor callbackExecutor) { - mMainExecutor.execute(() -> { - Consumer<String> cb = callback != null - ? (key) -> callbackExecutor.execute(() -> callback.accept(key)) - : null; - BubbleController.this.removeSuppressedSummaryIfNecessary(groupKey, cb); - }); - } - - @Override public void collapseStack() { mMainExecutor.execute(() -> { BubbleController.this.collapseStack(); @@ -1761,13 +1740,6 @@ public class BubbleController implements ConfigurationChangeListener { } @Override - public void openBubbleOverflow() { - mMainExecutor.execute(() -> { - BubbleController.this.openBubbleOverflow(); - }); - } - - @Override public boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children, IntConsumer removeCallback, Executor callbackExecutor) { @@ -1882,18 +1854,6 @@ public class BubbleController implements ConfigurationChangeListener { mMainExecutor.execute( () -> BubbleController.this.onNotificationPanelExpandedChanged(expanded)); } - - @Override - public void dump(PrintWriter pw, String[] args) { - try { - mMainExecutor.executeBlocking(() -> { - BubbleController.this.dump(pw, args); - mCachedState.dump(pw); - }); - } catch (InterruptedException e) { - Slog.e(TAG, "Failed to dump BubbleController in 2s"); - } - } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index fa86c8436647..c64133f0b668 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -1136,7 +1136,7 @@ public class BubbleData { /** * Description of current bubble data state. */ - public void dump(PrintWriter pw, String[] args) { + public void dump(PrintWriter pw) { pw.print("selected: "); pw.println(mSelectedBubble != null ? mSelectedBubble.getKey() @@ -1147,13 +1147,13 @@ public class BubbleData { pw.print("stack bubble count: "); pw.println(mBubbles.size()); for (Bubble bubble : mBubbles) { - bubble.dump(pw, args); + bubble.dump(pw); } pw.print("overflow bubble count: "); pw.println(mOverflowBubbles.size()); for (Bubble bubble : mOverflowBubbles) { - bubble.dump(pw, args); + bubble.dump(pw); } pw.print("summaryKeys: "); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index 4f225fff1451..840b2856270c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -1044,7 +1044,7 @@ public class BubbleExpandedView extends LinearLayout { /** * Description of current expanded view state. */ - public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { + public void dump(@NonNull PrintWriter pw) { pw.print("BubbleExpandedView"); pw.print(" taskId: "); pw.println(mTaskId); pw.print(" stackView: "); pw.println(mStackView); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 2d0be066beb5..5bf88b119661 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -299,7 +299,7 @@ public class BubbleStackView extends FrameLayout private BubblesNavBarGestureTracker mBubblesNavBarGestureTracker; /** Description of current animation controller state. */ - public void dump(PrintWriter pw, String[] args) { + public void dump(PrintWriter pw) { pw.println("Stack view state:"); String bubblesOnScreen = BubbleDebugConfig.formatBubblesString( @@ -313,8 +313,8 @@ public class BubbleStackView extends FrameLayout pw.print(" expandedContainerMatrix: "); pw.println(mExpandedViewContainer.getAnimationMatrix()); - mStackAnimationController.dump(pw, args); - mExpandedAnimationController.dump(pw, args); + mStackAnimationController.dump(pw); + mExpandedAnimationController.dump(pw); if (mExpandedBubble != null) { pw.println("Expanded bubble state:"); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java index 37b96ffe5cd1..0e97e9e74114 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java @@ -35,7 +35,6 @@ import androidx.annotation.Nullable; import com.android.wm.shell.common.annotations.ExternalThread; -import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.util.HashMap; @@ -91,18 +90,6 @@ public interface Bubbles { */ boolean isBubbleExpanded(String key); - /** @return {@code true} if stack of bubbles is expanded or not. */ - boolean isStackExpanded(); - - /** - * Removes a group key indicating that the summary for this group should no longer be - * suppressed. - * - * @param callback If removed, this callback will be called with the summary key of the group - */ - void removeSuppressedSummaryIfNecessary(String groupKey, Consumer<String> callback, - Executor callbackExecutor); - /** Tell the stack of bubbles to collapse. */ void collapseStack(); @@ -130,9 +117,6 @@ public interface Bubbles { /** Called for any taskbar changes. */ void onTaskbarChanged(Bundle b); - /** Open the overflow view. */ - void openBubbleOverflow(); - /** * We intercept notification entries (including group summaries) dismissed by the user when * there is an active bubble associated with it. We do this so that developers can still @@ -252,9 +236,6 @@ public interface Bubbles { */ void onUserRemoved(int removedUserId); - /** Description of current bubble state. */ - void dump(PrintWriter pw, String[] args); - /** Listener to find out about stack expansion / collapse events. */ interface BubbleExpandListener { /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java index b521cb6a3d38..ae434bcec6c4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java @@ -468,7 +468,7 @@ public class ExpandedAnimationController } /** Description of current animation controller state. */ - public void dump(PrintWriter pw, String[] args) { + public void dump(PrintWriter pw) { pw.println("ExpandedAnimationController state:"); pw.print(" isActive: "); pw.println(isActiveController()); pw.print(" animatingExpand: "); pw.println(mAnimatingExpand); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java index 0a1b4d70fb2b..4e2cbfd82fcc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java @@ -431,7 +431,7 @@ public class StackAnimationController extends } /** Description of current animation controller state. */ - public void dump(PrintWriter pw, String[] args) { + public void dump(PrintWriter pw) { pw.println("StackAnimationController state:"); pw.print(" isActive: "); pw.println(isActiveController()); pw.print(" restingStackPos: "); 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 d5875c03ccd2..e270edb800bd 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 @@ public class SystemWindows { } 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 85c8ebf454c9..83ba909e712d 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 final class SplitLayout implements DisplayInsetsController.OnInsetsChange 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 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange 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 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange 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 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange 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 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange 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 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange 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 final class SplitLayout implements DisplayInsetsController.OnInsetsChange 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 final class SplitLayout implements DisplayInsetsController.OnInsetsChange 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 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange } 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 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange 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/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java index e22c9517f4ab..8022e9b1cd81 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java @@ -66,6 +66,7 @@ public abstract class TvPipModule { @Provides static Optional<Pip> providePip( Context context, + ShellInit shellInit, ShellController shellController, TvPipBoundsState tvPipBoundsState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, @@ -84,6 +85,7 @@ public abstract class TvPipModule { return Optional.of( TvPipController.create( context, + shellInit, shellController, tvPipBoundsState, tvPipBoundsAlgorithm, 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 35a309a8352c..0cc545a7724a 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_BACKGROUND; 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 android.view.Choreographer; 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 @@ public abstract class WMShellConcurrencyModule { } /** - * 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 2ca9c3be8a69..4fe32556a94d 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.jank.InteractionJankMonitor; 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.TaskStackListenerImpl; 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; @@ -142,6 +145,7 @@ public abstract class WMShellModule { @Provides static BubbleController provideBubbleController(Context context, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellController shellController, BubbleData data, FloatingContentCoordinator floatingContentCoordinator, @@ -162,7 +166,7 @@ public abstract class WMShellModule { @ShellBackgroundThread ShellExecutor bgExecutor, TaskViewTransitions taskViewTransitions, SyncTransactionQueue syncQueue) { - return new BubbleController(context, shellInit, shellController, data, + return new BubbleController(context, shellInit, shellCommandHandler, shellController, data, null /* synchronizer */, floatingContentCoordinator, new BubbleDataRepository(context, launcherApps, mainExecutor), statusBarService, windowManager, windowManagerShellWrapper, userManager, @@ -574,6 +578,27 @@ public abstract class WMShellModule { } // + // 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 +608,8 @@ public abstract class WMShellModule { @ShellCreateTriggerOverride @Provides static Object provideIndependentShellComponentsToCreate( - SplitscreenPipMixedHandler splitscreenPipMixedHandler) { + SplitscreenPipMixedHandler splitscreenPipMixedHandler, + Optional<DesktopModeController> desktopModeController) { return new Object(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/FakeConnectivityInfoCollector.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java index 710e5f6eacd3..e62a63a910e7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/FakeConnectivityInfoCollector.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java @@ -14,20 +14,18 @@ * limitations under the License. */ -package com.android.systemui.statusbar.pipeline +package com.android.wm.shell.desktopmode; -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow +import android.os.SystemProperties; /** - * A test-friendly implementation of [ConnectivityInfoCollector] that just emits whatever value it - * receives in [emitValue]. + * Constants for desktop mode feature */ -class FakeConnectivityInfoCollector : ConnectivityInfoCollector { - private val _rawConnectivityInfoFlow = MutableStateFlow(RawConnectivityInfo()) - override val rawConnectivityInfoFlow = _rawConnectivityInfoFlow.asStateFlow() +public class DesktopModeConstants { - suspend fun emitValue(value: RawConnectivityInfo) { - _rawConnectivityInfoFlow.emit(value) - } + /** + * 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 000000000000..5849e163f0e2 --- /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/onehanded/OneHanded.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java index 76c0f41997ad..7129165a78dc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java @@ -37,16 +37,6 @@ public interface OneHanded { } /** - * Return one handed settings enabled or not. - */ - boolean isOneHandedEnabled(); - - /** - * Return swipe to notification settings enabled or not. - */ - boolean isSwipeToNotificationEnabled(); - - /** * Enters one handed mode. */ void startOneHanded(); @@ -80,9 +70,4 @@ public interface OneHanded { * transition start or finish */ void registerTransitionCallback(OneHandedTransitionCallback callback); - - /** - * Notifies when user switch complete - */ - void onUserSwitch(int userId); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 9149204b94ce..e0c4fe8c4fba 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -59,6 +59,7 @@ import com.android.wm.shell.sysui.KeyguardChangeListener; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.sysui.UserChangeListener; import java.io.PrintWriter; @@ -67,7 +68,7 @@ import java.io.PrintWriter; */ public class OneHandedController implements RemoteCallable<OneHandedController>, DisplayChangeController.OnDisplayChangingListener, ConfigurationChangeListener, - KeyguardChangeListener { + KeyguardChangeListener, UserChangeListener { private static final String TAG = "OneHandedController"; private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = @@ -76,8 +77,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, public static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode"; - private volatile boolean mIsOneHandedEnabled; - private volatile boolean mIsSwipeToNotificationEnabled; + private boolean mIsOneHandedEnabled; + private boolean mIsSwipeToNotificationEnabled; private boolean mIsShortcutEnabled; private boolean mTaskChangeToExit; private boolean mLockedDisabled; @@ -294,6 +295,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, mState.addSListeners(mTutorialHandler); mShellController.addConfigurationChangeListener(this); mShellController.addKeyguardChangeListener(this); + mShellController.addUserChangeListener(this); } public OneHanded asOneHanded() { @@ -627,7 +629,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, stopOneHanded(); } - private void onUserSwitch(int newUserId) { + @Override + public void onUserChanged(int newUserId, @NonNull Context userContext) { unregisterSettingObservers(); mUserId = newUserId; registerSettingObservers(newUserId); @@ -718,18 +721,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, } @Override - public boolean isOneHandedEnabled() { - // This is volatile so return directly - return mIsOneHandedEnabled; - } - - @Override - public boolean isSwipeToNotificationEnabled() { - // This is volatile so return directly - return mIsSwipeToNotificationEnabled; - } - - @Override public void startOneHanded() { mMainExecutor.execute(() -> { OneHandedController.this.startOneHanded(); @@ -770,13 +761,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, OneHandedController.this.registerTransitionCallback(callback); }); } - - @Override - public void onUserSwitch(int userId) { - mMainExecutor.execute(() -> { - OneHandedController.this.onUserSwitch(userId); - }); - } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java index 93172f82edd1..c06881ae6ad7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java @@ -51,12 +51,6 @@ public interface Pip { } /** - * Registers the session listener for the current user. - */ - default void registerSessionListenerForCurrentUser() { - } - - /** * Sets both shelf visibility and its height. * * @param visible visibility of shelf. 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 4942987742a0..281ea530e9e1 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.os.RemoteException; 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.PipBoundsState; 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 @@ public class PhonePipMenuController implements PipMenuController { 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 @@ public class PhonePipMenuController implements PipMenuController { private RemoteAction mCloseAction; private List<RemoteAction> mMediaActions; - private SyncRtSurfaceTransactionApplier mApplier; private int mMenuState; private PipMenuView mPipMenuView; @@ -150,6 +152,9 @@ public class PhonePipMenuController implements PipMenuController { mMainHandler = mainHandler; mSplitScreenController = splitScreenOptional; mPipUiEventLogger = pipUiEventLogger; + + mSurfaceControlTransactionFactory = + new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory(); } public boolean isMenuVisible() { @@ -194,7 +199,6 @@ public class PhonePipMenuController implements PipMenuController { return; } - mApplier = null; mSystemWindows.removeView(mPipMenuView); mPipMenuView = null; } @@ -289,7 +293,7 @@ public class PhonePipMenuController implements PipMenuController { willResizeMenu, withDelay, showResizeHandle, Debug.getCallers(5, " ")); } - if (!maybeCreateSyncApplier()) { + if (!checkPipMenuState()) { return; } @@ -312,7 +316,7 @@ public class PhonePipMenuController implements PipMenuController { return; } - if (!maybeCreateSyncApplier()) { + if (!checkPipMenuState()) { return; } @@ -328,18 +332,15 @@ public class PhonePipMenuController implements PipMenuController { 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 @@ public class PhonePipMenuController implements PipMenuController { 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/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index fc97f310ad4e..ac3407dd1ca1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -92,6 +92,7 @@ import com.android.wm.shell.sysui.KeyguardChangeListener; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.sysui.UserChangeListener; import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; @@ -105,7 +106,8 @@ import java.util.function.Consumer; * Manages the picture-in-picture (PIP) UI and states for Phones. */ public class PipController implements PipTransitionController.PipTransitionCallback, - RemoteCallable<PipController>, ConfigurationChangeListener, KeyguardChangeListener { + RemoteCallable<PipController>, ConfigurationChangeListener, KeyguardChangeListener, + UserChangeListener { private static final String TAG = "PipController"; private Context mContext; @@ -528,7 +530,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb }); mOneHandedController.ifPresent(controller -> { - controller.asOneHanded().registerTransitionCallback( + controller.registerTransitionCallback( new OneHandedTransitionCallback() { @Override public void onStartFinished(Rect bounds) { @@ -542,8 +544,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb }); }); + mMediaController.registerSessionListenerForCurrentUser(); + mShellController.addConfigurationChangeListener(this); mShellController.addKeyguardChangeListener(this); + mShellController.addUserChangeListener(this); } @Override @@ -557,6 +562,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb } @Override + public void onUserChanged(int newUserId, @NonNull Context userContext) { + // Re-register the media session listener when switching users + mMediaController.registerSessionListenerForCurrentUser(); + } + + @Override public void onConfigurationChanged(Configuration newConfig) { mPipBoundsAlgorithm.onConfigurationChanged(mContext); mTouchHandler.onConfigurationChanged(); @@ -644,10 +655,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb } } - private void registerSessionListenerForCurrentUser() { - mMediaController.registerSessionListenerForCurrentUser(); - } - private void onSystemUiStateChanged(boolean isValidState, int flag) { mTouchHandler.onSystemUiStateChanged(isValidState); } @@ -968,13 +975,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb } @Override - public void registerSessionListenerForCurrentUser() { - mMainExecutor.execute(() -> { - PipController.this.registerSessionListenerForCurrentUser(); - }); - } - - @Override public void setShelfHeight(boolean visible, int height) { mMainExecutor.execute(() -> { PipController.this.setShelfHeight(visible, height); 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 0f3ff36601fb..8e3376f163c1 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 @@ public class PipInputConsumer { "%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 abf1a9500e6d..89d85e4b292d 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 @@ public class PipResizeGestureHandler { 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/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java index a24d9618032d..4e1b0469eb96 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java @@ -32,6 +32,8 @@ import android.graphics.Rect; import android.os.RemoteException; import android.view.Gravity; +import androidx.annotation.NonNull; + import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.R; import com.android.wm.shell.WindowManagerShellWrapper; @@ -51,6 +53,8 @@ import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ConfigurationChangeListener; import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.sysui.UserChangeListener; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -64,7 +68,7 @@ import java.util.Set; public class TvPipController implements PipTransitionController.PipTransitionCallback, TvPipBoundsController.PipBoundsListener, TvPipMenuController.Delegate, TvPipNotificationController.Delegate, DisplayController.OnDisplaysChangedListener, - ConfigurationChangeListener { + ConfigurationChangeListener, UserChangeListener { private static final String TAG = "TvPipController"; static final boolean DEBUG = false; @@ -105,6 +109,11 @@ public class TvPipController implements PipTransitionController.PipTransitionCal private final PipMediaController mPipMediaController; private final TvPipNotificationController mPipNotificationController; private final TvPipMenuController mTvPipMenuController; + private final PipTransitionController mPipTransitionController; + private final TaskStackListenerImpl mTaskStackListener; + private final PipParamsChangedForwarder mPipParamsChangedForwarder; + private final DisplayController mDisplayController; + private final WindowManagerShellWrapper mWmShellWrapper; private final ShellExecutor mMainExecutor; private final TvPipImpl mImpl = new TvPipImpl(); @@ -121,6 +130,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal public static Pip create( Context context, + ShellInit shellInit, ShellController shellController, TvPipBoundsState tvPipBoundsState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, @@ -138,6 +148,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal ShellExecutor mainExecutor) { return new TvPipController( context, + shellInit, shellController, tvPipBoundsState, tvPipBoundsAlgorithm, @@ -157,6 +168,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal private TvPipController( Context context, + ShellInit shellInit, ShellController shellController, TvPipBoundsState tvPipBoundsState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, @@ -170,11 +182,12 @@ public class TvPipController implements PipTransitionController.PipTransitionCal TaskStackListenerImpl taskStackListener, PipParamsChangedForwarder pipParamsChangedForwarder, DisplayController displayController, - WindowManagerShellWrapper wmShell, + WindowManagerShellWrapper wmShellWrapper, ShellExecutor mainExecutor) { mContext = context; mMainExecutor = mainExecutor; mShellController = shellController; + mDisplayController = displayController; mTvPipBoundsState = tvPipBoundsState; mTvPipBoundsState.setDisplayId(context.getDisplayId()); @@ -193,16 +206,32 @@ public class TvPipController implements PipTransitionController.PipTransitionCal mAppOpsListener = pipAppOpsListener; mPipTaskOrganizer = pipTaskOrganizer; - pipTransitionController.registerPipTransitionCallback(this); + mPipTransitionController = pipTransitionController; + mPipParamsChangedForwarder = pipParamsChangedForwarder; + mTaskStackListener = taskStackListener; + mWmShellWrapper = wmShellWrapper; + shellInit.addInitCallback(this::onInit, this); + } + + private void onInit() { + mPipTransitionController.registerPipTransitionCallback(this); loadConfigurations(); - registerPipParamsChangedListener(pipParamsChangedForwarder); - registerTaskStackListenerCallback(taskStackListener); - registerWmShellPinnedStackListener(wmShell); - displayController.addDisplayWindowListener(this); + registerPipParamsChangedListener(mPipParamsChangedForwarder); + registerTaskStackListenerCallback(mTaskStackListener); + registerWmShellPinnedStackListener(mWmShellWrapper); + registerSessionListenerForCurrentUser(); + mDisplayController.addDisplayWindowListener(this); mShellController.addConfigurationChangeListener(this); + mShellController.addUserChangeListener(this); + } + + @Override + public void onUserChanged(int newUserId, @NonNull Context userContext) { + // Re-register the media session listener when switching users + registerSessionListenerForCurrentUser(); } @Override @@ -679,11 +708,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal } private class TvPipImpl implements Pip { - @Override - public void registerSessionListenerForCurrentUser() { - mMainExecutor.execute(() -> { - TvPipController.this.registerSessionListenerForCurrentUser(); - }); - } + // Not used } } 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 b2961518b66a..93c75299a64b 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 @@ public enum ShellProtoLogGroup implements IProtoLogGroup { 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 7e83d2fa0a0b..21fc01e554c8 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_HOME; 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, ? 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // 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 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // 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/sysui/KeyguardChangeListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/KeyguardChangeListener.java index 1c0b35894acd..9df863163b50 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/KeyguardChangeListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/KeyguardChangeListener.java @@ -21,13 +21,13 @@ package com.android.wm.shell.sysui; */ public interface KeyguardChangeListener { /** - * Notifies the Shell that the keyguard is showing (and if so, whether it is occluded). + * Called when the keyguard is showing (and if so, whether it is occluded). */ default void onKeyguardVisibilityChanged(boolean visible, boolean occluded, boolean animatingDismiss) {} /** - * Notifies the Shell when the keyguard dismiss animation has finished. + * Called when the keyguard dismiss animation has finished. * * TODO(b/206741900) deprecate this path once we're able to animate the PiP window as part of * keyguard dismiss animation. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java index 52ffb46bb39c..57993948886b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java @@ -25,7 +25,9 @@ import static android.content.pm.ActivityInfo.CONFIG_UI_MODE; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SYSUI_EVENTS; +import android.content.Context; import android.content.pm.ActivityInfo; +import android.content.pm.UserInfo; import android.content.res.Configuration; import androidx.annotation.NonNull; @@ -36,6 +38,7 @@ import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.annotations.ExternalThread; import java.io.PrintWriter; +import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -53,6 +56,9 @@ public class ShellController { new CopyOnWriteArrayList<>(); private final CopyOnWriteArrayList<KeyguardChangeListener> mKeyguardChangeListeners = new CopyOnWriteArrayList<>(); + private final CopyOnWriteArrayList<UserChangeListener> mUserChangeListeners = + new CopyOnWriteArrayList<>(); + private Configuration mLastConfiguration; @@ -102,6 +108,22 @@ public class ShellController { mKeyguardChangeListeners.remove(listener); } + /** + * Adds a new user-change listener. The user change callbacks are not made in any + * particular order. + */ + public void addUserChangeListener(UserChangeListener listener) { + mUserChangeListeners.remove(listener); + mUserChangeListeners.add(listener); + } + + /** + * Removes an existing user-change listener. + */ + public void removeUserChangeListener(UserChangeListener listener) { + mUserChangeListeners.remove(listener); + } + @VisibleForTesting void onConfigurationChanged(Configuration newConfig) { // The initial config is send on startup and doesn't trigger listener callbacks @@ -144,6 +166,8 @@ public class ShellController { @VisibleForTesting void onKeyguardVisibilityChanged(boolean visible, boolean occluded, boolean animatingDismiss) { + ProtoLog.v(WM_SHELL_SYSUI_EVENTS, "Keyguard visibility changed: visible=%b " + + "occluded=%b animatingDismiss=%b", visible, occluded, animatingDismiss); for (KeyguardChangeListener listener : mKeyguardChangeListeners) { listener.onKeyguardVisibilityChanged(visible, occluded, animatingDismiss); } @@ -151,17 +175,35 @@ public class ShellController { @VisibleForTesting void onKeyguardDismissAnimationFinished() { + ProtoLog.v(WM_SHELL_SYSUI_EVENTS, "Keyguard dismiss animation finished"); for (KeyguardChangeListener listener : mKeyguardChangeListeners) { listener.onKeyguardDismissAnimationFinished(); } } + @VisibleForTesting + void onUserChanged(int newUserId, @NonNull Context userContext) { + ProtoLog.v(WM_SHELL_SYSUI_EVENTS, "User changed: id=%d", newUserId); + for (UserChangeListener listener : mUserChangeListeners) { + listener.onUserChanged(newUserId, userContext); + } + } + + @VisibleForTesting + void onUserProfilesChanged(@NonNull List<UserInfo> profiles) { + ProtoLog.v(WM_SHELL_SYSUI_EVENTS, "User profiles changed"); + for (UserChangeListener listener : mUserChangeListeners) { + listener.onUserProfilesChanged(profiles); + } + } + public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); pw.println(innerPrefix + "mConfigChangeListeners=" + mConfigChangeListeners.size()); pw.println(innerPrefix + "mLastConfiguration=" + mLastConfiguration); pw.println(innerPrefix + "mKeyguardChangeListeners=" + mKeyguardChangeListeners.size()); + pw.println(innerPrefix + "mUserChangeListeners=" + mUserChangeListeners.size()); } /** @@ -220,5 +262,17 @@ public class ShellController { mMainExecutor.execute(() -> ShellController.this.onKeyguardDismissAnimationFinished()); } + + @Override + public void onUserChanged(int newUserId, @NonNull Context userContext) { + mMainExecutor.execute(() -> + ShellController.this.onUserChanged(newUserId, userContext)); + } + + @Override + public void onUserProfilesChanged(@NonNull List<UserInfo> profiles) { + mMainExecutor.execute(() -> + ShellController.this.onUserProfilesChanged(profiles)); + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java index 254c253b0042..2108c824ac6f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java @@ -16,9 +16,14 @@ package com.android.wm.shell.sysui; +import android.content.Context; +import android.content.pm.UserInfo; import android.content.res.Configuration; +import androidx.annotation.NonNull; + import java.io.PrintWriter; +import java.util.List; /** * General interface for notifying the Shell of common SysUI events like configuration or keyguard @@ -59,4 +64,14 @@ public interface ShellInterface { * Notifies the Shell when the keyguard dismiss animation has finished. */ default void onKeyguardDismissAnimationFinished() {} + + /** + * Notifies the Shell when the user changes. + */ + default void onUserChanged(int newUserId, @NonNull Context userContext) {} + + /** + * Notifies the Shell when a profile belonging to the user changes. + */ + default void onUserProfilesChanged(@NonNull List<UserInfo> profiles) {} } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/UserChangeListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/UserChangeListener.java new file mode 100644 index 000000000000..3d0909f6128d --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/UserChangeListener.java @@ -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.wm.shell.sysui; + +import android.content.Context; +import android.content.pm.UserInfo; + +import androidx.annotation.NonNull; + +import java.util.List; + +/** + * Callbacks for when the user or user's profiles changes. + */ +public interface UserChangeListener { + /** + * Called when the current (parent) user changes. + */ + default void onUserChanged(int newUserId, @NonNull Context userContext) {} + + /** + * Called when a profile belonging to the user changes. + */ + default void onUserProfilesChanged(@NonNull List<UserInfo> profiles) {} +} 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 9335438cea50..26d0ec637ccf 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_KEYGUARD_GOING_AWAY; 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 @@ public class Transitions implements RemoteCallable<Transitions> { 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 @@ public class Transitions implements RemoteCallable<Transitions> { } } + 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 @@ public class Transitions implements RemoteCallable<Transitions> { @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 98b5ee9f0cfb..dc3deb1a927c 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.R; 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 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL 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 506a4c0f90f3..5e64a06e0326 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> 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 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } 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 f865649b6bbc..b29c436d0d51 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 com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIO 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.clearInvocations; 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.ITaskOrganizer; 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 @@ public class ShellTaskOrganizerTests extends ShellTestCase { 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 @@ public class ShellTaskOrganizerTests extends ShellTestCase { 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 32f1587752cb..ff1d2990a82a 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 @@ public class TaskViewTest extends ShellTestCase { 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 @@ public class TaskViewTest extends ShellTestCase { 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 @@ public class TaskViewTest extends ShellTestCase { mTaskView.surfaceCreated(mock(SurfaceHolder.class)); verify(mViewListener).onInitialized(); + assertThat(mTaskView.isInitialized()).isTrue(); verify(mViewListener).onTaskVisibilityChanged(eq(mTaskInfo.taskId), eq(true)); } @@ -223,6 +226,7 @@ public class TaskViewTest extends ShellTestCase { verify(mOrganizer).removeListener(eq(mTaskView)); verify(mViewListener).onReleased(); + assertThat(mTaskView.isInitialized()).isFalse(); } @Test @@ -270,6 +274,7 @@ public class TaskViewTest extends ShellTestCase { 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 @@ public class TaskViewTest extends ShellTestCase { 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 @@ public class TaskViewTest extends ShellTestCase { 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 95725bbfd855..695550dd8fa5 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 @@ public class SplitLayoutTests extends ShellTestCase { } 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 000000000000..58f20da34943 --- /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/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java index 90645ce4747d..cf8297eec061 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java @@ -171,6 +171,11 @@ public class OneHandedControllerTest extends OneHandedTestCase { } @Test + public void testControllerRegistersUserChangeListener() { + verify(mMockShellController, times(1)).addUserChangeListener(any()); + } + + @Test public void testDefaultShouldNotInOneHanded() { // Assert default transition state is STATE_NONE assertThat(mSpiedTransitionState.getState()).isEqualTo(STATE_NONE); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java index 9ed8d84d665f..eb5726bebb74 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java @@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -77,9 +78,9 @@ import java.util.Set; public class PipControllerTest extends ShellTestCase { private PipController mPipController; private ShellInit mShellInit; + private ShellController mShellController; @Mock private ShellCommandHandler mMockShellCommandHandler; - @Mock private ShellController mMockShellController; @Mock private DisplayController mMockDisplayController; @Mock private PhonePipMenuController mMockPhonePipMenuController; @Mock private PipAppOpsListener mMockPipAppOpsListener; @@ -110,8 +111,10 @@ public class PipControllerTest extends ShellTestCase { return null; }).when(mMockExecutor).execute(any()); mShellInit = spy(new ShellInit(mMockExecutor)); + mShellController = spy(new ShellController(mShellInit, mMockShellCommandHandler, + mMockExecutor)); mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler, - mMockShellController, mMockDisplayController, mMockPipAppOpsListener, + mShellController, mMockDisplayController, mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm, mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState, @@ -135,12 +138,22 @@ public class PipControllerTest extends ShellTestCase { @Test public void instantiatePipController_registerConfigChangeListener() { - verify(mMockShellController, times(1)).addConfigurationChangeListener(any()); + verify(mShellController, times(1)).addConfigurationChangeListener(any()); } @Test public void instantiatePipController_registerKeyguardChangeListener() { - verify(mMockShellController, times(1)).addKeyguardChangeListener(any()); + verify(mShellController, times(1)).addKeyguardChangeListener(any()); + } + + @Test + public void instantiatePipController_registerUserChangeListener() { + verify(mShellController, times(1)).addUserChangeListener(any()); + } + + @Test + public void instantiatePipController_registerMediaListener() { + verify(mMockPipMediaController, times(1)).registerSessionListenerForCurrentUser(); } @Test @@ -167,7 +180,7 @@ public class PipControllerTest extends ShellTestCase { ShellInit shellInit = new ShellInit(mMockExecutor); assertNull(PipController.create(spyContext, shellInit, mMockShellCommandHandler, - mMockShellController, mMockDisplayController, mMockPipAppOpsListener, + mShellController, mMockDisplayController, mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm, mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState, @@ -264,4 +277,11 @@ public class PipControllerTest extends ShellTestCase { verify(mMockPipBoundsState).setKeepClearAreas(Set.of(keepClearArea), Set.of()); } + + @Test + public void onUserChangeRegisterMediaListener() { + reset(mMockPipMediaController); + mShellController.asShell().onUserChanged(100, mContext); + verify(mMockPipMediaController, times(1)).registerSessionListenerForCurrentUser(); + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java index 39e58ffcf9c7..d6ddba9e927d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java @@ -17,11 +17,15 @@ package com.android.wm.shell.sysui; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import android.content.Context; +import android.content.pm.UserInfo; import android.content.res.Configuration; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; @@ -35,6 +39,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; @SmallTest @@ -42,22 +48,29 @@ import java.util.Locale; @TestableLooper.RunWithLooper(setAsMainLooper = true) public class ShellControllerTest extends ShellTestCase { + private static final int TEST_USER_ID = 100; + @Mock private ShellInit mShellInit; @Mock private ShellCommandHandler mShellCommandHandler; @Mock private ShellExecutor mExecutor; + @Mock + private Context mTestUserContext; private ShellController mController; private TestConfigurationChangeListener mConfigChangeListener; private TestKeyguardChangeListener mKeyguardChangeListener; + private TestUserChangeListener mUserChangeListener; + @Before public void setUp() { MockitoAnnotations.initMocks(this); mKeyguardChangeListener = new TestKeyguardChangeListener(); mConfigChangeListener = new TestConfigurationChangeListener(); + mUserChangeListener = new TestUserChangeListener(); mController = new ShellController(mShellInit, mShellCommandHandler, mExecutor); mController.onConfigurationChanged(getConfigurationCopy()); } @@ -68,6 +81,46 @@ public class ShellControllerTest extends ShellTestCase { } @Test + public void testAddUserChangeListener_ensureCallback() { + mController.addUserChangeListener(mUserChangeListener); + + mController.onUserChanged(TEST_USER_ID, mTestUserContext); + assertTrue(mUserChangeListener.userChanged == 1); + assertTrue(mUserChangeListener.lastUserContext == mTestUserContext); + } + + @Test + public void testDoubleAddUserChangeListener_ensureSingleCallback() { + mController.addUserChangeListener(mUserChangeListener); + mController.addUserChangeListener(mUserChangeListener); + + mController.onUserChanged(TEST_USER_ID, mTestUserContext); + assertTrue(mUserChangeListener.userChanged == 1); + assertTrue(mUserChangeListener.lastUserContext == mTestUserContext); + } + + @Test + public void testAddRemoveUserChangeListener_ensureNoCallback() { + mController.addUserChangeListener(mUserChangeListener); + mController.removeUserChangeListener(mUserChangeListener); + + mController.onUserChanged(TEST_USER_ID, mTestUserContext); + assertTrue(mUserChangeListener.userChanged == 0); + assertTrue(mUserChangeListener.lastUserContext == null); + } + + @Test + public void testUserProfilesChanged() { + mController.addUserChangeListener(mUserChangeListener); + + ArrayList<UserInfo> profiles = new ArrayList<>(); + profiles.add(mock(UserInfo.class)); + profiles.add(mock(UserInfo.class)); + mController.onUserProfilesChanged(profiles); + assertTrue(mUserChangeListener.lastUserProfiles.equals(profiles)); + } + + @Test public void testAddKeyguardChangeListener_ensureCallback() { mController.addKeyguardChangeListener(mKeyguardChangeListener); @@ -332,4 +385,27 @@ public class ShellControllerTest extends ShellTestCase { dismissAnimationFinished++; } } + + private class TestUserChangeListener implements UserChangeListener { + // Counts of number of times each of the callbacks are called + public int userChanged; + public int lastUserId; + public Context lastUserContext; + public int userProfilesChanged; + public List<? extends UserInfo> lastUserProfiles; + + + @Override + public void onUserChanged(int newUserId, @NonNull Context userContext) { + userChanged++; + lastUserId = newUserId; + lastUserContext = userContext; + } + + @Override + public void onUserProfilesChanged(@NonNull List<UserInfo> profiles) { + userProfilesChanged++; + lastUserProfiles = profiles; + } + } } 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 226843eca64e..e11be31aa40e 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 com.google.common.truth.Truth.assertThat; 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 @@ public class WindowDecorationTests extends ShellTestCase { mMockSurfaceControlFinishT = createMockSurfaceControlTransaction(); doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory) - .create(any(), any(), any(), anyBoolean()); + .create(any(), any(), any()); } @Test @@ -148,8 +147,7 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 @@ public class WindowDecorationTests extends ShellTestCase { 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 8756f1e2266d..c08f5a293e1d 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -45,6 +45,7 @@ import java.nio.ByteOrder; 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 @@ final public class MediaCodec { 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 @@ final public class MediaCodec { 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 @@ final public class MediaCodec { */ public final void start() { native_start(); - synchronized(mBufferLock) { - cacheBuffers(true /* input */); - cacheBuffers(false /* input */); - } } private native final void native_start(); @@ -2380,8 +2377,10 @@ final public class MediaCodec { */ 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 @@ final public class MediaCodec { + "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 @@ final public class MediaCodec { + "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 @@ final public class MediaCodec { int res = native_dequeueInputBuffer(timeoutUs); if (res >= 0) { synchronized(mBufferLock) { - validateInputByteBuffer(mCachedInputBuffers, res); + validateInputByteBufferLocked(mCachedInputBuffers, res); } } return res; @@ -3573,10 +3572,10 @@ final public class MediaCodec { 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 @@ final public class MediaCodec { 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 @@ final public class MediaCodec { 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 @@ final public class MediaCodec { } } - 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 @@ final public class MediaCodec { } } - 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 @@ final public class MediaCodec { } } - 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 @@ final public class MediaCodec { } } - 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 @@ final public class MediaCodec { } } - 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 @@ final public class MediaCodec { } } - 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 @@ final public class MediaCodec { + "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 @@ final public class MediaCodec { + "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 @@ final public class MediaCodec { } 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 @@ final public class MediaCodec { } 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 @@ final public class MediaCodec { } 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 @@ final public class MediaCodec { } 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 dd36b49e824d..481d26d15141 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 a900d1379027..7bef7fae5cdf 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 201877877916..9a51181105ad 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 8f7d7d2ca399..0720cf58f523 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 65c8edc20aac..086956b7f40a 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 4c879d0123d3..cbacce8becba 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 402c615e232e..9e0f9107da61 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 48974a7bd40f..d1f157af8194 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 89b91e69bac0..f6da021703f5 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 13c3f412f518..a21a89a5e7f8 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 d843629a43c1..f16e1c50f0fa 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 75d974ab2c19..316cefa99e01 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 c146ef529d64..f7452dff115b 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 1d1472ea5454..0c0c7378333f 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 262a35feab65..926ad8464ccf 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 d85fa5657c4b..28c80e9bb268 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 8c34a1f0f72a..b6f15903ecbd 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 9ddba82177d5..e17adb1546ba 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 90bcaa4ba386..e1d033cd289b 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 7b959f49162b..eb3a05cc2d5e 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 155104ae81dc..48a33f61a427 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 951d417639f6..84fca3db8720 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 31126a803f8f..ca999db843b5 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 3bd4d46b6cef..b75e4df9c762 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 2979e78ca5c1..cbc2724a59c6 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 426a6d215380..c787941cab1f 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 dc3691b713f4..dc794082a4fb 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 426a6d215380..c787941cab1f 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 426a6d215380..c787941cab1f 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 8360f0152bfe..175ac5d7b980 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 9b1aa3a274fc..381380800e97 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 d0f2c641982f..cf154664753f 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 0677864d1f46..49244078105e 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 e75c13c4aecd..bb2f59b622fb 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 d986ecf47260..0402ac2f5719 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 022063cfe20d..bcd6ad1a3ea6 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 d166e1b97a38..9c12e95cf5c8 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 ba8b1ad1fe3d..b1ac23618444 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 b7761dd6ebcb..41410cbc3288 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 911426cecd7d..ffd80ec67a0a 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 296989299cfe..842fb8fed9a7 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 670bcae60bc6..3d12c02c0c81 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 5d6aaeb0a513..7dfc86ed801d 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 80ac7e4e4752..92546da3f56d 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 dad8668c9782..52d15f1af116 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 b6cf48e54f72..f66312084e4b 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 3fd7f439fae6..ef73b59078c8 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 eb84599798ec..02c99277b77e 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 e52975627aac..6dbb2b47dd88 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 0e66858f2d3a..559383ad875f 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 598f65f60583..e3f8ba8b8051 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 8eae4d0cdde8..8ff60319e572 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 50d7c7f59f65..009875d2ba5c 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 2a5fbfb2a156..8a4586689bd6 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 5b0ad98aa2d5..95274177e888 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 08ec2b1e7805..6dc569711e23 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 dc2036f0ac88..4531fb1ecefb 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 201fb48bc25b..87f5870d6a61 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 e6f1bcbbe768..5f567c6b4fb9 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 c42679bff7f3..49dfb92ef8d2 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 cd206e6275cd..93dfb44e079d 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 fc998e73a16c..9971f8651c12 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 d0b8c0dfa6ea..4733c28d23bc 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 a005f4dc2bd0..2269df193c23 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 fa759a61cf06..771598535e45 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 b6014ce72c65..975f60f3c5d5 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 5b0d684cd9f4..66e2da872045 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 7138113c8b74..16b840bd9f5f 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 ae9c19f9f9a5..111dd34c5d91 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 40271f71afdb..700aae13822e 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 e85e6afa3509..ea9bd8629356 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 792ca39a8bf4..f116e6f4f311 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 ace42767eb27..10b814d4b98a 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 946f69c3030b..c0aafdcd4da3 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 b309db6c9537..ce53dfebc15d 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 f4ae45234bf5..0f9ee52c3fac 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 6bbc051fad77..df917917799a 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 eb9cbfdd6a7e..7f8283501b96 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 3d99eda91210..43040ef6281a 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 c2f241c33b85..ad8b6fdcf4c0 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 13ea9c91996f..be5222a12f83 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 9ff2170181d8..cadc5cf3548a 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 0492dac1b191..0c49387acc63 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 7f67bd236efb..6ca0cc3e5d60 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 522b5ee5dfe9..88bdba4e5e4d 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 9a90a7f994f3..118363005f1d 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 d42aeaff755d..a6c40b07941c 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 65813a7977d5..a949dc933a60 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 e111f8a82578..4d16cecca95c 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 f0453d1e7df1..71ecd4642742 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 64d7af0d9f03..cd8b6fb56e0b 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 8c1e83d046db..4e1b1dda6099 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 63ce593d7c77..9215ce38a21f 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 8c1e83d046db..4e1b1dda6099 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 4702b6a72179..3c8119993a0d 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 b1211a5c376c..4b6e69288af2 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 2b6250b887f9..c27b55eb695c 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 8386c1aa5559..eaacfb835de5 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 9318c8d7392c..dfc7bf91c0c4 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 6dee1e38df4d..8f435fb9145f 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 6e33e386d897..b2003e5efbc6 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 c35ee7a4c142..b3a29063586d 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 8a6d853e7818..ed8638016c34 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 a92ef7c2873b..83d95a32d76a 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 dee7f9dadf49..ea370f617c67 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 09b3d7adb72c..970f54990b4f 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 dab4279f88dc..53dc6e5440ad 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 63a732d2e7a9..476daf971ecb 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 1f717886fb38..962ec34b54a6 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 592810e0e651..cc1f29171855 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 aa01af7d88c8..65744b21f056 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 c2f203546667..6b1411d3655a 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 0bc9cc252d07..af51c6881962 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 0410bd6ab43d..c32da85ceab3 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 03e3ef9b2cae..8e102e48413b 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 cac1b6c47050..9e22b904607d 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 7d09027983a3..edbd1805b756 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 cae38142e8e7..c66b6cf937d7 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 1995e705bd66..ed781085bbc0 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 973d7d01fcc9..2a85d311a5c4 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 c4780850e5fe..e1e50ae4cd51 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 b4667a85ed3f..1a6648fc70a5 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 809702226ea1..991dcad785d2 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 2321ace413db..f1f736c7c671 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 11cb9c1b54c9..0e60caae7e71 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 b9c4030d9d0e..a822e185479a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -600,6 +600,9 @@ public class Utils { * 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 d1f10a640dbf..86d2eb85479f 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 @@ public class SecureSettings { 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 4aadf72930aa..6a70230701f6 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 @@ public class SecureSettingsValidators { 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 e7d444cb07e5..8ff6d12e3817 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 6edf13addbca..78dea891bc12 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 4b07eaf780e4..fa855ab495a2 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -20,6 +20,7 @@ cwren@google.com 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 @@ jamesoleary@google.com 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 @@ nickchameyev@google.com 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 @@ twickham@google.com 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/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp index 40218de94258..325ede613de8 100644 --- a/packages/SystemUI/compose/features/Android.bp +++ b/packages/SystemUI/compose/features/Android.bp @@ -30,6 +30,7 @@ android_library { ], 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 0aea99d4e960..eada40e6a40d 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" - package="com.android.systemui.compose.features"> - + 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 000000000000..2bf1937a1c1e --- /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 000000000000..5c9358f99858 --- /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 40504dc30c33..b0f5cc112120 100644 --- a/packages/SystemUI/compose/gallery/Android.bp +++ b/packages/SystemUI/compose/gallery/Android.bp @@ -27,6 +27,7 @@ android_library { srcs: [ "src/**/*.kt", + ":SystemUI-tests-utils", ], resource_dirs: [ @@ -45,6 +46,14 @@ android_library { "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 c341867bfb59..bb98fb350a2e 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.Composable 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 @@ object GalleryAppScreens { 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 @@ object GalleryAppScreens { "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 @@ fun GalleryApp( 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 @@ fun GalleryApp( } 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 @@ fun GalleryApp( 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) } + + if (showControls) { + ConfigurationControls( + theme, + fontScale, + layoutDirection, + onChangeTheme, + onChangeLayoutDirection, + onChangeFontScale, + Modifier.padding(horizontal = 16.dp), + ) - Spacer(Modifier.height(4.dp)) + Spacer(Modifier.height(4.dp)) + } - MainContent() + 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 000000000000..2f0df7790ffd --- /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 467dac044b79..d7d0d721b01c 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 @@ class ChildScreen( ) : 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 @@ fun NavGraphBuilder.screen(screen: Screen, navController: NavController) { 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 000000000000..0966c3233ad5 --- /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-land/dimens.xml b/packages/SystemUI/res-keyguard/values-land/dimens.xml index 4e92884f39f3..a4e7a5f12db4 100644 --- a/packages/SystemUI/res-keyguard/values-land/dimens.xml +++ b/packages/SystemUI/res-keyguard/values-land/dimens.xml @@ -22,7 +22,6 @@ <dimen name="keyguard_eca_top_margin">0dp</dimen> <dimen name="keyguard_eca_bottom_margin">2dp</dimen> <dimen name="keyguard_password_height">26dp</dimen> - <dimen name="num_pad_entry_row_margin_bottom">0dp</dimen> <!-- The size of PIN text in the PIN unlock method. --> <integer name="scaled_password_text_size">26</integer> diff --git a/packages/SystemUI/res-keyguard/values-sw360dp-land/dimens.xml b/packages/SystemUI/res-keyguard/values-sw360dp-land/dimens.xml index f465be4f5228..0421135b31a5 100644 --- a/packages/SystemUI/res-keyguard/values-sw360dp-land/dimens.xml +++ b/packages/SystemUI/res-keyguard/values-sw360dp-land/dimens.xml @@ -22,7 +22,6 @@ <dimen name="keyguard_eca_top_margin">4dp</dimen> <dimen name="keyguard_eca_bottom_margin">4dp</dimen> <dimen name="keyguard_password_height">50dp</dimen> - <dimen name="num_pad_entry_row_margin_bottom">4dp</dimen> <!-- The size of PIN text in the PIN unlock method. --> <integer name="scaled_password_text_size">40</integer> diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml index acf3e4dcf02a..32871f0abb4f 100644 --- a/packages/SystemUI/res-keyguard/values/dimens.xml +++ b/packages/SystemUI/res-keyguard/values/dimens.xml @@ -86,7 +86,7 @@ <!-- Spacing around each button used for PIN view --> <dimen name="num_pad_key_width">72dp</dimen> - <dimen name="num_pad_entry_row_margin_bottom">16dp</dimen> + <dimen name="num_pad_entry_row_margin_bottom">12dp</dimen> <dimen name="num_pad_row_margin_bottom">6dp</dimen> <dimen name="num_pad_key_margin_end">12dp</dimen> diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index babe924c4615..8fa22048cd97 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 7a57293f58bd..3bf44a4b85a4 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/layout/new_status_bar_wifi_group.xml b/packages/SystemUI/res/layout/new_status_bar_wifi_group.xml new file mode 100644 index 000000000000..753ba2f21faf --- /dev/null +++ b/packages/SystemUI/res/layout/new_status_bar_wifi_group.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 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. +*/ +--> +<com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/wifi_combo" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center_vertical" > + + <include layout="@layout/status_bar_wifi_group_inner" /> + +</com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView> diff --git a/packages/SystemUI/res/layout/status_bar_wifi_group.xml b/packages/SystemUI/res/layout/status_bar_wifi_group.xml index 35cce25d45a7..6cb6993bb762 100644 --- a/packages/SystemUI/res/layout/status_bar_wifi_group.xml +++ b/packages/SystemUI/res/layout/status_bar_wifi_group.xml @@ -18,70 +18,11 @@ --> <com.android.systemui.statusbar.StatusBarWifiView xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/wifi_combo" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center_vertical" > - <com.android.keyguard.AlphaOptimizedLinearLayout - android:id="@+id/wifi_group" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:layout_marginStart="2.5dp" - > - <FrameLayout - android:id="@+id/inout_container" - android:layout_height="17dp" - android:layout_width="wrap_content" - android:gravity="center_vertical" > - <ImageView - android:id="@+id/wifi_in" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:src="@drawable/ic_activity_down" - android:visibility="gone" - android:paddingEnd="2dp" - /> - <ImageView - android:id="@+id/wifi_out" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:src="@drawable/ic_activity_up" - android:paddingEnd="2dp" - android:visibility="gone" - /> - </FrameLayout> - <FrameLayout - android:id="@+id/wifi_combo" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:gravity="center_vertical" > - <com.android.systemui.statusbar.AlphaOptimizedImageView - android:id="@+id/wifi_signal" - android:layout_height="@dimen/status_bar_wifi_signal_size" - android:layout_width="@dimen/status_bar_wifi_signal_size" /> - </FrameLayout> + <include layout="@layout/status_bar_wifi_group_inner" /> - <View - android:id="@+id/wifi_signal_spacer" - android:layout_width="@dimen/status_bar_wifi_signal_spacer_width" - android:layout_height="4dp" - android:visibility="gone" /> - - <!-- Looks like CarStatusBar uses this... --> - <ViewStub - android:id="@+id/connected_device_signals_stub" - android:layout="@layout/connected_device_signal" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <View - android:id="@+id/wifi_airplane_spacer" - android:layout_width="@dimen/status_bar_airplane_spacer_width" - android:layout_height="4dp" - android:visibility="gone" - /> - </com.android.keyguard.AlphaOptimizedLinearLayout> -</com.android.systemui.statusbar.StatusBarWifiView> +</com.android.systemui.statusbar.StatusBarWifiView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml b/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml new file mode 100644 index 000000000000..0ea0653ab89f --- /dev/null +++ b/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 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. +*/ +--> + +<merge xmlns:android="http://schemas.android.com/apk/res/android"> + + <com.android.keyguard.AlphaOptimizedLinearLayout + android:id="@+id/wifi_group" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center_vertical" + android:layout_marginStart="2.5dp" + > + <FrameLayout + android:id="@+id/inout_container" + android:layout_height="17dp" + android:layout_width="wrap_content" + android:gravity="center_vertical" > + <ImageView + android:id="@+id/wifi_in" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:src="@drawable/ic_activity_down" + android:visibility="gone" + android:paddingEnd="2dp" + /> + <ImageView + android:id="@+id/wifi_out" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:src="@drawable/ic_activity_up" + android:paddingEnd="2dp" + android:visibility="gone" + /> + </FrameLayout> + <FrameLayout + android:id="@+id/wifi_combo" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:gravity="center_vertical" > + <com.android.systemui.statusbar.AlphaOptimizedImageView + android:id="@+id/wifi_signal" + android:layout_height="@dimen/status_bar_wifi_signal_size" + android:layout_width="@dimen/status_bar_wifi_signal_size" /> + </FrameLayout> + + <View + android:id="@+id/wifi_signal_spacer" + android:layout_width="@dimen/status_bar_wifi_signal_spacer_width" + android:layout_height="4dp" + android:visibility="gone" /> + + <!-- Looks like CarStatusBar uses this... --> + <ViewStub + android:id="@+id/connected_device_signals_stub" + android:layout="@layout/connected_device_signal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <View + android:id="@+id/wifi_airplane_spacer" + android:layout_width="@dimen/status_bar_airplane_spacer_width" + android:layout_height="4dp" + android:visibility="gone" + /> + </com.android.keyguard.AlphaOptimizedLinearLayout> +</merge> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index f34472158d1b..229858413f99 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 7f3caeca5a62..e4fefc7c6705 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 60130e1086ef..47e2d2ccd13e 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.DeviceEmulationSpec 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 @@ class ViewScreenshotTestRule(emulationSpec: DeviceEmulationSpec) : TestRule { .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 2739d59dbf00..c2fda82cefdc 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 @@ class AnimatableClockView @JvmOverloads constructor( 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 @@ class AnimatableClockView @JvmOverloads constructor( 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 @@ class AnimatableClockView @JvmOverloads constructor( } 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 @@ class AnimatableClockView @JvmOverloads constructor( // 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 @@ class AnimatableClockView @JvmOverloads constructor( } 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 @@ class AnimatableClockView @JvmOverloads constructor( 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/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java index b29dc835a6f4..22bffda33918 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.accessibility.AccessibilityManager; 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 @@ public class RotationButtonController { 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 class RotationButtonController { } public void onTaskbarStateChange(boolean visible, boolean stashed) { + mTaskBarVisible = visible; if (getRotationButton() == null) { return; } @@ -438,9 +441,12 @@ public class RotationButtonController { * 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 @@ public class RotationButtonController { } } } - diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 206b8bee323c..916410856b20 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -88,6 +88,7 @@ public class KeyguardClockSwitch extends RelativeLayout { private int mClockSwitchYAmount; @VisibleForTesting boolean mChildrenAreLaidOut = false; + @VisibleForTesting boolean mAnimateOnLayout = true; public KeyguardClockSwitch(Context context, AttributeSet attrs) { super(context, attrs); @@ -305,7 +306,7 @@ public class KeyguardClockSwitch extends RelativeLayout { 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 cf50f7f8524b..d1589b23454d 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 @@ public class UdfpsController implements DozeReceiver { 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 @@ public class UdfpsController implements DozeReceiver { 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 49e378e4a76f..d96476fbf087 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 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable { 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 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable { } 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 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable { } } + 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 47ea27ff8ccb..08393386c27f 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.FrameLayout; 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 @@ import java.text.NumberFormat; * @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 @@ final class WirelessChargingLayout extends FrameLayout { "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 @@ final class WirelessChargingLayout extends FrameLayout { 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 f32ea353bf50..e549a96079bd 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 @@ package com.android.systemui.dagger; import android.app.INotificationManager; import android.content.Context; +import android.service.dreams.IDreamManager; import androidx.annotation.Nullable; @@ -213,6 +214,7 @@ public abstract class SystemUIModule { ShadeController shadeController, @Nullable IStatusBarService statusBarService, INotificationManager notificationManager, + IDreamManager dreamManager, NotificationVisibilityProvider visibilityProvider, NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, @@ -230,6 +232,7 @@ public abstract class SystemUIModule { shadeController, statusBarService, notificationManager, + dreamManager, visibilityProvider, interruptionStateProvider, zenModeController, @@ -238,7 +241,6 @@ public abstract class SystemUIModule { notifCollection, notifPipeline, sysUiState, - dumpManager, sysuiMainExecutor)); } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java index 7e4a108aadf1..823255c38a84 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 @@ public class DreamOverlayStatusBarView extends ConstraintLayout { } void setExtraStatusBarItemViews(List<View> views) { - mSystemStatusViewGroup.removeAllViews(); + removeAllStatusBarItemViews(); views.forEach(view -> mSystemStatusViewGroup.addView(view)); } @@ -121,4 +121,8 @@ public class DreamOverlayStatusBarView extends ConstraintLayout { 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 65cfae1ac14b..6f505504b186 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 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve 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 5250d44761b9..7d9f1059f3b8 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 @@ import dagger.Provides; 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 7299aa597e60..f8682635897c 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -155,7 +155,11 @@ public class Flags { public static final ReleasedFlag STATUS_BAR_LETTERBOX_APPEARANCE = new ReleasedFlag(603, false); - public static final UnreleasedFlag NEW_STATUS_BAR_PIPELINE = new UnreleasedFlag(604, true); + public static final UnreleasedFlag NEW_STATUS_BAR_PIPELINE_BACKEND = + new UnreleasedFlag(604, true); + + public static final UnreleasedFlag NEW_STATUS_BAR_PIPELINE_FRONTEND = + new UnreleasedFlag(605, true); /***************************************/ // 700 - dialer/calls @@ -174,11 +178,16 @@ public class Flags { 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 +242,7 @@ public class Flags { // 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 ca65d12e87e6..da5819a7f3bc 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.ImageView.ScaleType; 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 class GlobalActionsDialogLite implements DialogInterface.OnDismissListene 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 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene protected ViewGroup mContainer; + private final OnBackInvokedCallback mOnBackInvokedCallback = () -> { + logOnBackInvocation(); + dismiss(); + }; + @VisibleForTesting protected GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() { @@ -2221,6 +2230,16 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene } }; + + // 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 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene 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 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene @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 3eb3c80f4081..6dfbd426ef30 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 @@ public class KeyguardService extends Service { 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 @@ public class KeyguardService extends Service { 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 @@ public class KeyguardService extends Service { 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 dbf218a115cb..d4ef4675392d 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 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, 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 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, 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 19c6249a12c0..c4e3d4e4c1b5 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 @@ object KeyguardBottomAreaViewBinder { 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 01d5e5c493ce..e3ebac60febb 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 @@ constructor( 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 @@ constructor( 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 @@ constructor( 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 985ab623764a..b1de27d262cf 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 @@ data class KeyguardQuickAffordanceViewModel( 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 c858bc3e2c81..c2a87649adef 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 @@ public class LogModule { 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 @@ public class LogModule { @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 000000000000..bd0d298ebdee --- /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 237b5053ea2c..32600fba61a4 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 @@ package com.android.systemui.media 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 @@ class KeyguardMediaController @Inject constructor( @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 @@ class KeyguardMediaController @Inject constructor( } }) + 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 @@ class KeyguardMediaController @Inject constructor( 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 @@ class KeyguardMediaController @Inject constructor( 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 30ba476abce2..c8826757355a 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.ContentResolver import android.content.Context import android.content.Intent import android.content.IntentFilter +import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.ImageDecoder @@ -57,8 +59,8 @@ import com.android.systemui.dagger.qualifiers.Main 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 @@ class MediaDataManager( } 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 @@ class MediaDataManager( } // 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 @@ class MediaDataManager( 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 @@ class MediaDataManager( 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 @@ class MediaDataManager( } } + 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 926002060da7..ae4c7c73a2ea 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.animation.ValueAnimator 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,12 +38,12 @@ import com.android.keyguard.KeyguardViewController 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 @@ -47,6 +52,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController 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 @@ -85,15 +91,23 @@ class MediaHierarchyManager @Inject constructor( 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, 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 @@ -521,6 +535,23 @@ class MediaHierarchyManager @Inject constructor( 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() { @@ -1036,7 +1067,6 @@ class MediaHierarchyManager @Inject constructor( } 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 @@ -1044,7 +1074,7 @@ class MediaHierarchyManager @Inject constructor( !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. @@ -1116,7 +1146,7 @@ class MediaHierarchyManager @Inject constructor( 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 4ef98cf13a00..bec130b75b61 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 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements 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 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements } 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 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements } } - 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 310469dd5415..35baf0131b9d 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 @@ package com.android.systemui.media.dialog; 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 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { } @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 0fa326573c9c..2b5d6fd63995 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 @@ class MediaOutputBroadcastDialogFactory @Inject constructor( 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 @@ class MediaOutputBroadcastDialogFactory @Inject constructor( 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 52dbfe572474..dad6544a87ba 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 static android.provider.Settings.ACTION_BLUETOOTH_SETTINGS; 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 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, 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 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, DialogLaunchAnimator dialogLaunchAnimator, Optional<NearbyMediaDevicesManager> nearbyMediaDevicesManagerOptional, AudioManager audioManager, - PowerExemptionManager powerExemptionManager) { + PowerExemptionManager powerExemptionManager, + KeyguardManager keyGuardManager) { mContext = context; mPackageName = packageName; mMediaSessionManager = mediaSessionManager; @@ -163,6 +166,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, 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 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, } } - Drawable getAppSourceIcon() { + Drawable getAppSourceIconFromPackage() { if (mPackageName.isEmpty()) { return null; } @@ -421,6 +425,24 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, || 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 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, ActivityLaunchAnimator.Controller controller = mDialogLaunchAnimator.createActivityLaunchController(view); - if (controller == null) { + if (controller == null || (mKeyGuardManager != null + && mKeyGuardManager.isKeyguardLocked())) { mCallback.dismissDialog(); } @@ -771,7 +794,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback, 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 fc4773d3c6dd..fbd0079f8dc0 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 @@ public class MediaOutputDialog extends MediaOutputBaseDialog { } @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 8249a7c0779c..543efed8378e 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 @@ class MediaOutputDialogFactory @Inject constructor( 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 @@ class MediaOutputDialogFactory @Inject constructor( 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 e077fed7805d..c5448713970c 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 androidx.annotation.Nullable; 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 @@ import javax.inject.Inject; * 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 class MediaDreamSentinel extends CoreStartable { 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 @@ public class MediaDreamSentinel extends CoreStartable { 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 2278938c398e..3a0ac1b7d9b0 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 @@ abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>( 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 196ea222e50d..00a22f20e94d 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 @@ class MediaTttChipControllerReceiver @Inject constructor( 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 @@ class MediaTttChipControllerReceiver @Inject constructor( .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 0834a5ae75f6..e27bfb34ee3e 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.model.PeopleTileModel 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 @@ class PeopleViewModel( * 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 @@ class PeopleViewModel( * 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/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java index eeb1010693fc..2a6cf66995ea 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java @@ -80,7 +80,8 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader FeatureFlags featureFlags, VariableDateViewController.Factory variableDateViewControllerFactory, BatteryMeterViewController batteryMeterViewController, - StatusBarContentInsetsProvider statusBarContentInsetsProvider) { + StatusBarContentInsetsProvider statusBarContentInsetsProvider, + StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory) { super(view); mPrivacyIconsController = headerPrivacyIconsController; mStatusBarIconController = statusBarIconController; @@ -103,7 +104,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader mView.requireViewById(R.id.date_clock) ); - mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, featureFlags); + mIconManager = tintedIconManagerFactory.create(mIconContainer); mDemoModeReceiver = new ClockDemoModeReceiver(mClockView); mColorExtractor = colorExtractor; mOnColorsChangedListener = (extractor, which) -> { diff --git a/packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt b/packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt index 56a187429af6..db7c1fd86be0 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 @@ class RippleShader internal constructor(rippleShape: RippleShape = RippleShape.C 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 @@ class RippleShader internal constructor(rippleShape: RippleShape = RippleShape.C 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 @@ class RippleShader internal constructor(rippleShape: RippleShape = RippleShape.C 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 8b0120177268..60c8f3719a2e 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 @@ open class RippleView(context: Context?, attrs: AttributeSet?) : View(context, a 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 @@ open class RippleView(context: Context?, attrs: AttributeSet?) : View(context, a 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 000000000000..f7c4dadc6605 --- /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 39f35a59ff42..77797601ca5a 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 @@ interface ImageCapture { 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 258c4360922d..246265b2c202 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 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 @@ open class ImageCaptureImpl @Inject constructor( 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 @@ open class ImageCaptureImpl @Inject constructor( } @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 4397d3d85d62..a918e5d9e106 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!") - 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}") + // 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) + } } + + 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 000000000000..3580010cc1e8 --- /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 000000000000..ba809f676f1e --- /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 000000000000..9654e03e506e --- /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 7bf3217e5f15..8b37aab87665 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 android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS; 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 @@ import javax.inject.Inject; 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 @@ public class TakeScreenshotService extends Service { }; /** 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 @@ public class TakeScreenshotService extends Service { 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 @@ public class TakeScreenshotService extends Service { if (DEBUG_SERVICE) { Log.d(TAG, "onUnbind"); } - if (mScreenshot != null) { - mScreenshot.removeWindow(); - mScreenshot = null; - } + mScreenshot.removeWindow(); unregisterReceiver(mCloseSystemDialogs); return false; } @@ -161,10 +160,7 @@ public class TakeScreenshotService extends Service { @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 @@ public class TakeScreenshotService extends Service { 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 3e44258744f2..fdb01000b837 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 android.app.Service; 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 @@ import dagger.multibindings.IntoMap; @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/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt index 5e908d9cd29f..1558ac533137 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt @@ -76,6 +76,6 @@ interface UserTracker : UserContentResolverProvider, UserContextProvider { * Notifies that the current user's profiles have changed. */ @JvmDefault - fun onProfilesChanged(profiles: List<UserInfo>) {} + fun onProfilesChanged(profiles: List<@JvmSuppressWildcards UserInfo>) {} } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt index 0f9ac360cbe1..fab70fc2eebd 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt @@ -77,6 +77,7 @@ import javax.inject.Named class LargeScreenShadeHeaderController @Inject constructor( @Named(LARGE_SCREEN_SHADE_HEADER) private val header: View, private val statusBarIconController: StatusBarIconController, + private val tintedIconManagerFactory: StatusBarIconController.TintedIconManager.Factory, private val privacyIconsController: HeaderPrivacyIconsController, private val insetsProvider: StatusBarContentInsetsProvider, private val configurationController: ConfigurationController, @@ -259,7 +260,7 @@ class LargeScreenShadeHeaderController @Inject constructor( batteryMeterViewController.ignoreTunerUpdates() batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE) - iconManager = StatusBarIconController.TintedIconManager(iconContainer, featureFlags) + iconManager = tintedIconManagerFactory.create(iconContainer) iconManager.setTint( Utils.getColorAttrDefaultColor(header.context, android.R.attr.textColorPrimary) ) diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index cf416c52bf3a..e6d10228dc55 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.ColorFilter; 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; @@ -448,7 +447,6 @@ public final class NotificationPanelViewController extends PanelViewController { */ private boolean mQsAnimatorExpand; private boolean mIsLaunchTransitionFinished; - private boolean mOnlyAffordanceInThisMotion; private ValueAnimator mQsSizeChangeAnimator; private boolean mQsScrimEnabled = true; @@ -726,6 +724,7 @@ public final class NotificationPanelViewController extends PanelViewController { AccessibilityManager accessibilityManager, @DisplayId int displayId, KeyguardUpdateMonitor keyguardUpdateMonitor, MetricsLogger metricsLogger, + ShadeLogger shadeLogger, ConfigurationController configurationController, Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder, StatusBarTouchableRegionManager statusBarTouchableRegionManager, @@ -792,6 +791,7 @@ public final class NotificationPanelViewController extends PanelViewController { panelExpansionStateManager, ambientState, interactionJankMonitor, + shadeLogger, systemClock); mView = view; mVibratorHelper = vibratorHelper; @@ -1887,6 +1887,8 @@ public final class NotificationPanelViewController extends PanelViewController { } if (mQsExpansionAnimator != null) { mInitialHeightOnTouch = mQsExpansionHeight; + mShadeLog.logMotionEvent(event, + "onQsIntercept: down action, QS tracking enabled"); mQsTracking = true; traceQsJank(true /* startTracing */, false /* wasCancelled */); mNotificationStackScrollLayoutController.cancelLongPress(); @@ -1914,12 +1916,16 @@ public final class NotificationPanelViewController extends PanelViewController { 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(); @@ -1935,6 +1941,7 @@ public final class NotificationPanelViewController extends PanelViewController { case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: trackMovement(event); + mShadeLog.logMotionEvent(event, "onQsIntercept: up action, QS tracking disabled"); mQsTracking = false; break; } @@ -1972,7 +1979,6 @@ public final class NotificationPanelViewController extends PanelViewController { private void initDownStates(MotionEvent event) { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { - mOnlyAffordanceInThisMotion = false; mQsTouchAboveFalsingThreshold = mQsFullyExpanded; mDozingOnDown = isDozing(); mDownX = event.getX(); @@ -2111,6 +2117,7 @@ public final class NotificationPanelViewController extends PanelViewController { && 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; @@ -2125,6 +2132,8 @@ public final class NotificationPanelViewController extends PanelViewController { if (!mQsExpandImmediate && mQsTracking) { onQsTouch(event); if (!mConflictingQsExpansionGesture && !mSplitShadeEnabled) { + mShadeLog.logMotionEvent(event, + "handleQsTouch: not immediate expand or conflicting gesture"); return true; } } @@ -2192,6 +2201,7 @@ public final class NotificationPanelViewController extends PanelViewController { 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; @@ -2274,6 +2284,7 @@ public final class NotificationPanelViewController extends PanelViewController { 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; @@ -2300,6 +2311,7 @@ public final class NotificationPanelViewController extends PanelViewController { 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; @@ -2309,6 +2321,8 @@ public final class NotificationPanelViewController extends PanelViewController { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: + mShadeLog.logMotionEvent(event, + "onQsTouch: up/cancel action, QS tracking disabled"); mQsTracking = false; mTrackingPointer = -1; trackMovement(event); @@ -3131,8 +3145,8 @@ public final class NotificationPanelViewController extends PanelViewController { positionClockAndNotifications(); } } - if (mQsExpandImmediate || mQsExpanded && !mQsTracking && mQsExpansionAnimator == null - && !mQsExpansionFromOverscroll) { + if (mQsExpandImmediate || (mQsExpanded && !mQsTracking && mQsExpansionAnimator == null + && !mQsExpansionFromOverscroll)) { float t; if (mKeyguardShowing) { @@ -3792,13 +3806,12 @@ public final class NotificationPanelViewController extends PanelViewController { * * @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); @@ -4224,6 +4237,7 @@ public final class NotificationPanelViewController extends PanelViewController { || 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() @@ -4231,14 +4245,10 @@ public final class NotificationPanelViewController extends PanelViewController { && 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()) { @@ -4729,7 +4739,7 @@ public final class NotificationPanelViewController extends PanelViewController { * change. */ public void showAodUi() { - setDozing(true /* dozing */, false /* animate */, null); + setDozing(true /* dozing */, false /* animate */); mStatusBarStateController.setUpcomingState(KEYGUARD); mEntryManager.updateNotifications("showAodUi"); mStatusBarStateListener.onStateChanged(KEYGUARD); @@ -4810,6 +4820,8 @@ public final class NotificationPanelViewController extends PanelViewController { } } else if (!mQsExpanded && mQsExpansionAnimator == null) { setQsExpansion(mQsMinExpansionHeight + mLastOverscroll); + } else { + mShadeLog.v("onLayoutChange: qs expansion not set"); } updateExpandedHeight(getExpandedHeight()); updateHeader(); diff --git a/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java index 4aad245f96fd..73eaa852e345 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 @@ public abstract class PanelViewController { private final InteractionJankMonitor mInteractionJankMonitor; protected final SystemClock mSystemClock; + protected final ShadeLogger mShadeLog; + protected abstract void onExpandingFinished(); protected void onExpandingStarted() { @@ -242,6 +244,7 @@ public abstract class PanelViewController { PanelExpansionStateManager panelExpansionStateManager, AmbientState ambientState, InteractionJankMonitor interactionJankMonitor, + ShadeLogger shadeLogger, SystemClock systemClock) { keyguardStateController.addCallback(new KeyguardStateController.Callback() { @Override @@ -254,6 +257,7 @@ public abstract class PanelViewController { mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mLockscreenGestureLogger = lockscreenGestureLogger; mPanelExpansionStateManager = panelExpansionStateManager; + mShadeLog = shadeLogger; TouchHandler touchHandler = createTouchHandler(); mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override @@ -1275,9 +1279,16 @@ public abstract class PanelViewController { @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 @@ public abstract class PanelViewController { // 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 000000000000..f1e44ce5736e --- /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/BaseStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarWifiView.kt new file mode 100644 index 000000000000..4d53064d047d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarWifiView.kt @@ -0,0 +1,34 @@ +/* + * 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 + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout + +/** + * A temporary base class that's shared between our old status bar wifi view implementation + * ([StatusBarWifiView]) and our new status bar wifi view implementation + * ([ModernStatusBarWifiView]). + * + * Once our refactor is over, we should be able to delete this go-between class and the old view + * class. + */ +abstract class BaseStatusBarWifiView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttrs: Int = 0, +) : FrameLayout(context, attrs, defStyleAttrs), StatusIconDisplayable diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 0280e0b729a9..c04bc8289f81 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 @@ public class StatusBarStateControllerImpl implements } @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/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java index a6986d797833..5aee62e3e89f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java @@ -28,7 +28,6 @@ import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; -import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; @@ -41,8 +40,7 @@ import java.util.ArrayList; /** * Start small: StatusBarWifiView will be able to layout from a WifiIconState */ -public class StatusBarWifiView extends FrameLayout implements DarkReceiver, - StatusIconDisplayable { +public class StatusBarWifiView extends BaseStatusBarWifiView implements DarkReceiver { private static final String TAG = "StatusBarWifiView"; /// Used to show etc dots @@ -80,11 +78,6 @@ public class StatusBarWifiView extends FrameLayout implements DarkReceiver, super(context, attrs, defStyleAttr); } - public StatusBarWifiView(Context context, AttributeSet attrs, int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - public void setSlot(String slot) { mSlot = slot; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java index 2b3190159ecd..2cc77384fb2a 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 @@ public interface SysuiStatusBarStateController extends StatusBarStateController 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/connectivity/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java index 3c449ad270ef..7097568c4adf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java @@ -23,7 +23,7 @@ import com.android.settingslib.SignalIcon.IconGroup; /** */ public class WifiIcons { - static final int[] WIFI_FULL_ICONS = { + public static final int[] WIFI_FULL_ICONS = { com.android.internal.R.drawable.ic_wifi_signal_0, com.android.internal.R.drawable.ic_wifi_signal_1, com.android.internal.R.drawable.ic_wifi_signal_2, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt index a509fcaad4ee..8f8813b80b5f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt @@ -31,11 +31,13 @@ import android.os.UserHandle import android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS import android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS import android.util.Log +import android.view.ContextThemeWrapper import android.view.View import android.view.ViewGroup import com.android.settingslib.Utils import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags @@ -46,6 +48,7 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.settings.UserTracker +import com.android.systemui.shared.regionsampling.RegionSamplingInstance import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.DeviceProvisionedController @@ -60,22 +63,23 @@ import javax.inject.Inject */ @SysUISingleton class LockscreenSmartspaceController @Inject constructor( - private val context: Context, - private val featureFlags: FeatureFlags, - private val smartspaceManager: SmartspaceManager, - private val activityStarter: ActivityStarter, - private val falsingManager: FalsingManager, - private val secureSettings: SecureSettings, - private val userTracker: UserTracker, - private val contentResolver: ContentResolver, - private val configurationController: ConfigurationController, - private val statusBarStateController: StatusBarStateController, - private val deviceProvisionedController: DeviceProvisionedController, - private val bypassController: KeyguardBypassController, - private val execution: Execution, - @Main private val uiExecutor: Executor, - @Main private val handler: Handler, - optionalPlugin: Optional<BcSmartspaceDataPlugin> + private val context: Context, + private val featureFlags: FeatureFlags, + private val smartspaceManager: SmartspaceManager, + private val activityStarter: ActivityStarter, + private val falsingManager: FalsingManager, + private val secureSettings: SecureSettings, + private val userTracker: UserTracker, + private val contentResolver: ContentResolver, + private val configurationController: ConfigurationController, + private val statusBarStateController: StatusBarStateController, + private val deviceProvisionedController: DeviceProvisionedController, + private val bypassController: KeyguardBypassController, + private val execution: Execution, + @Main private val uiExecutor: Executor, + @Background private val bgExecutor: Executor, + @Main private val handler: Handler, + optionalPlugin: Optional<BcSmartspaceDataPlugin> ) { companion object { private const val TAG = "LockscreenSmartspaceController" @@ -86,15 +90,36 @@ class LockscreenSmartspaceController @Inject constructor( // Smartspace can be used on multiple displays, such as when the user casts their screen private var smartspaceViews = mutableSetOf<SmartspaceView>() + private var regionSamplingInstances = + mutableMapOf<SmartspaceView, RegionSamplingInstance>() + + private val regionSamplingEnabled = + featureFlags.isEnabled(Flags.REGION_SAMPLING) private var showNotifications = false private var showSensitiveContentForCurrentUser = false private var showSensitiveContentForManagedUser = false private var managedUserHandle: UserHandle? = null + private val updateFun = object : RegionSamplingInstance.UpdateColorCallback { + override fun updateColors() { + updateTextColorFromRegionSampler() + } + } + var stateChangeListener = object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { smartspaceViews.add(v as SmartspaceView) + + var regionSamplingInstance = RegionSamplingInstance( + v, + uiExecutor, + bgExecutor, + regionSamplingEnabled, + updateFun + ) + regionSamplingInstance.startRegionSampler() + regionSamplingInstances.put(v, regionSamplingInstance) connectSession() updateTextColorFromWallpaper() @@ -104,6 +129,10 @@ class LockscreenSmartspaceController @Inject constructor( override fun onViewDetachedFromWindow(v: View) { smartspaceViews.remove(v as SmartspaceView) + var regionSamplingInstance = regionSamplingInstances.getValue(v) + regionSamplingInstance.stopRegionSampler() + regionSamplingInstances.remove(v) + if (smartspaceViews.isEmpty()) { disconnect() } @@ -332,9 +361,29 @@ class LockscreenSmartspaceController @Inject constructor( } } + private fun updateTextColorFromRegionSampler() { + smartspaceViews.forEach { + val isRegionDark = regionSamplingInstances.getValue(it).currentRegionDarkness() + val themeID = if (isRegionDark.isDark) { + R.style.Theme_SystemUI + } else { + R.style.Theme_SystemUI_LightWallpaper + } + val themedContext = ContextThemeWrapper(context, themeID) + val wallpaperTextColor = + Utils.getColorAttrDefaultColor(themedContext, R.attr.wallpaperTextColor) + it.setPrimaryTextColor(wallpaperTextColor) + } + } + private fun updateTextColorFromWallpaper() { - val wallpaperTextColor = Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor) - smartspaceViews.forEach { it.setPrimaryTextColor(wallpaperTextColor) } + if (!regionSamplingEnabled) { + val wallpaperTextColor = + Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor) + smartspaceViews.forEach { it.setPrimaryTextColor(wallpaperTextColor) } + } else { + updateTextColorFromRegionSampler() + } } private fun reloadSmartspace() { 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 952bafbe6eb3..79d883b32a98 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.Color; 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 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable * 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 9998fe41b775..3f6586c37b5d 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 static com.android.systemui.statusbar.phone.NotificationIconAreaControlle 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 @@ public class NotificationStackScrollLayoutController { 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 65ba5adddd60..e754d5db4186 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 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp 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 7da1d6c085b0..08b1c1993e76 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.PackageManager; 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 @@ public class CentralSurfacesImpl extends CoreStartable implements @VisibleForTesting DozeServiceHost mDozeServiceHost; private boolean mWakeUpComingFromTouch; - private PointF mWakeUpTouchLocation; private LightRevealScrim mLightRevealScrim; private PowerButtonReveal mPowerButtonReveal; @@ -619,8 +617,6 @@ public class CentralSurfacesImpl extends CoreStartable implements 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 @@ public class CentralSurfacesImpl extends CoreStartable implements 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 @@ public class CentralSurfacesImpl extends CoreStartable implements PowerManager.WAKE_REASON_APPLICATION, "com.android.systemui:full_screen_intent"); mWakeUpComingFromTouch = false; - mWakeUpTouchLocation = null; } } @@ -3242,7 +3227,7 @@ public class CentralSurfacesImpl extends CoreStartable implements || (mDozing && mDozeParameters.shouldControlScreenOff() && visibleNotOccludedOrWillBe); - mNotificationPanelViewController.setDozing(mDozing, animate, mWakeUpTouchLocation); + mNotificationPanelViewController.setDozing(mDozing, animate); updateQsExpansionEnabled(); Trace.endSection(); } @@ -3573,7 +3558,6 @@ public class CentralSurfacesImpl extends CoreStartable implements mLaunchCameraWhenFinishedWaking = false; mDeviceInteractive = false; mWakeUpComingFromTouch = false; - mWakeUpTouchLocation = null; updateVisibleToUser(); updateNotificationPanelTouchState(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java index fc8e7d5f6aa2..deb6150f773b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -225,6 +225,7 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da public void addDemoWifiView(WifiIconState state) { Log.d(TAG, "addDemoWifiView: "); + // TODO(b/238425913): Migrate this view to {@code ModernStatusBarWifiView}. StatusBarWifiView view = StatusBarWifiView.fromContext(mContext, state.slot); int viewIndex = getChildCount(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 30b640b583e6..ed186ab6a10b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -40,6 +40,7 @@ import com.android.systemui.demomode.DemoModeCommandReceiver; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; +import com.android.systemui.statusbar.BaseStatusBarWifiView; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.StatusBarMobileView; import com.android.systemui.statusbar.StatusBarWifiView; @@ -47,12 +48,16 @@ import com.android.systemui.statusbar.StatusIconDisplayable; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; +import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags; +import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView; +import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel; import com.android.systemui.util.Assert; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; +import javax.inject.Provider; public interface StatusBarIconController { @@ -128,8 +133,12 @@ public interface StatusBarIconController { private final DarkIconDispatcher mDarkIconDispatcher; private int mIconHPadding; - public DarkIconManager(LinearLayout linearLayout, FeatureFlags featureFlags) { - super(linearLayout, featureFlags); + public DarkIconManager( + LinearLayout linearLayout, + FeatureFlags featureFlags, + StatusBarPipelineFlags statusBarPipelineFlags, + Provider<WifiViewModel> wifiViewModelProvider) { + super(linearLayout, featureFlags, statusBarPipelineFlags, wifiViewModelProvider); mIconHPadding = mContext.getResources().getDimensionPixelSize( R.dimen.status_bar_icon_padding); mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class); @@ -183,14 +192,40 @@ public interface StatusBarIconController { mDarkIconDispatcher.removeDarkReceiver(mDemoStatusIcons); super.exitDemoMode(); } + + @SysUISingleton + public static class Factory { + private final FeatureFlags mFeatureFlags; + private final StatusBarPipelineFlags mStatusBarPipelineFlags; + private final Provider<WifiViewModel> mWifiViewModelProvider; + + @Inject + public Factory( + FeatureFlags featureFlags, + StatusBarPipelineFlags statusBarPipelineFlags, + Provider<WifiViewModel> wifiViewModelProvider) { + mFeatureFlags = featureFlags; + mStatusBarPipelineFlags = statusBarPipelineFlags; + mWifiViewModelProvider = wifiViewModelProvider; + } + + public DarkIconManager create(LinearLayout group) { + return new DarkIconManager( + group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider); + } + } } /** */ class TintedIconManager extends IconManager { private int mColor; - public TintedIconManager(ViewGroup group, FeatureFlags featureFlags) { - super(group, featureFlags); + public TintedIconManager( + ViewGroup group, + FeatureFlags featureFlags, + StatusBarPipelineFlags statusBarPipelineFlags, + Provider<WifiViewModel> wifiViewModelProvider) { + super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider); } @Override @@ -223,14 +258,22 @@ public interface StatusBarIconController { @SysUISingleton public static class Factory { private final FeatureFlags mFeatureFlags; + private final StatusBarPipelineFlags mStatusBarPipelineFlags; + private final Provider<WifiViewModel> mWifiViewModelProvider; @Inject - public Factory(FeatureFlags featureFlags) { + public Factory( + FeatureFlags featureFlags, + StatusBarPipelineFlags statusBarPipelineFlags, + Provider<WifiViewModel> wifiViewModelProvider) { mFeatureFlags = featureFlags; + mStatusBarPipelineFlags = statusBarPipelineFlags; + mWifiViewModelProvider = wifiViewModelProvider; } public TintedIconManager create(ViewGroup group) { - return new TintedIconManager(group, mFeatureFlags); + return new TintedIconManager( + group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider); } } } @@ -239,8 +282,10 @@ public interface StatusBarIconController { * Turns info from StatusBarIconController into ImageViews in a ViewGroup. */ class IconManager implements DemoModeCommandReceiver { - private final FeatureFlags mFeatureFlags; protected final ViewGroup mGroup; + private final FeatureFlags mFeatureFlags; + private final StatusBarPipelineFlags mStatusBarPipelineFlags; + private final Provider<WifiViewModel> mWifiViewModelProvider; protected final Context mContext; protected final int mIconSize; // Whether or not these icons show up in dumpsys @@ -254,9 +299,15 @@ public interface StatusBarIconController { protected ArrayList<String> mBlockList = new ArrayList<>(); - public IconManager(ViewGroup group, FeatureFlags featureFlags) { - mFeatureFlags = featureFlags; + public IconManager( + ViewGroup group, + FeatureFlags featureFlags, + StatusBarPipelineFlags statusBarPipelineFlags, + Provider<WifiViewModel> wifiViewModelProvider) { mGroup = group; + mFeatureFlags = featureFlags; + mStatusBarPipelineFlags = statusBarPipelineFlags; + mWifiViewModelProvider = wifiViewModelProvider; mContext = group.getContext(); mIconSize = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); @@ -308,7 +359,7 @@ public interface StatusBarIconController { return addIcon(index, slot, blocked, holder.getIcon()); case TYPE_WIFI: - return addSignalIcon(index, slot, holder.getWifiState()); + return addWifiIcon(index, slot, holder.getWifiState()); case TYPE_MOBILE: return addMobileIcon(index, slot, holder.getMobileState()); @@ -327,9 +378,17 @@ public interface StatusBarIconController { } @VisibleForTesting - protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) { - StatusBarWifiView view = onCreateStatusBarWifiView(slot); - view.applyWifiState(state); + protected StatusIconDisplayable addWifiIcon(int index, String slot, WifiIconState state) { + final BaseStatusBarWifiView view; + if (mStatusBarPipelineFlags.isNewPipelineFrontendEnabled()) { + view = onCreateModernStatusBarWifiView(slot); + // When [ModernStatusBarWifiView] is created, it will automatically apply the + // correct view state so we don't need to call applyWifiState. + } else { + StatusBarWifiView wifiView = onCreateStatusBarWifiView(slot); + wifiView.applyWifiState(state); + view = wifiView; + } mGroup.addView(view, index, onCreateLayoutParams()); if (mIsInDemoMode) { @@ -359,6 +418,11 @@ public interface StatusBarIconController { return view; } + private ModernStatusBarWifiView onCreateModernStatusBarWifiView(String slot) { + return ModernStatusBarWifiView.constructAndBind( + mContext, slot, mWifiViewModelProvider.get()); + } + private StatusBarMobileView onCreateStatusBarMobileView(String slot) { StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, slot); return view; @@ -415,9 +479,8 @@ public interface StatusBarIconController { onSetIcon(viewIndex, holder.getIcon()); return; case TYPE_WIFI: - onSetSignalIcon(viewIndex, holder.getWifiState()); + onSetWifiIcon(viewIndex, holder.getWifiState()); return; - case TYPE_MOBILE: onSetMobileIcon(viewIndex, holder.getMobileState()); default: @@ -425,10 +488,16 @@ public interface StatusBarIconController { } } - public void onSetSignalIcon(int viewIndex, WifiIconState state) { - StatusBarWifiView wifiView = (StatusBarWifiView) mGroup.getChildAt(viewIndex); - if (wifiView != null) { - wifiView.applyWifiState(state); + public void onSetWifiIcon(int viewIndex, WifiIconState state) { + View view = mGroup.getChildAt(viewIndex); + if (view instanceof StatusBarWifiView) { + ((StatusBarWifiView) view).applyWifiState(state); + } else if (view instanceof ModernStatusBarWifiView) { + // ModernStatusBarWifiView will automatically apply state based on its callbacks, so + // we don't need to call applyWifiState. + } else { + throw new IllegalStateException("View at " + viewIndex + " must be of type " + + "StatusBarWifiView or ModernStatusBarWifiView"); } if (mIsInDemoMode) { 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 d058b75fd1b1..53e08ea8e10d 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.os.PowerManager 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 @@ class UnlockedScreenOffAnimationController @Inject constructor( } 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/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java index c4e7a8a2c17b..627cfb718d91 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java @@ -287,6 +287,7 @@ public abstract class StatusBarViewModule { PanelExpansionStateManager panelExpansionStateManager, FeatureFlags featureFlags, StatusBarIconController statusBarIconController, + StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory, StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager, KeyguardStateController keyguardStateController, NotificationPanelViewController notificationPanelViewController, @@ -308,6 +309,7 @@ public abstract class StatusBarViewModule { panelExpansionStateManager, featureFlags, statusBarIconController, + darkIconManagerFactory, statusBarHideIconsForBouncerManager, keyguardStateController, notificationPanelViewController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java index 29b4d5bfbc82..84bb82beee1c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java @@ -130,6 +130,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue private final StatusBarIconController mStatusBarIconController; private final CarrierConfigTracker mCarrierConfigTracker; private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; + private final StatusBarIconController.DarkIconManager.Factory mDarkIconManagerFactory; private final SecureSettings mSecureSettings; private final Executor mMainExecutor; private final DumpManager mDumpManager; @@ -185,6 +186,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue PanelExpansionStateManager panelExpansionStateManager, FeatureFlags featureFlags, StatusBarIconController statusBarIconController, + StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory, StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager, KeyguardStateController keyguardStateController, NotificationPanelViewController notificationPanelViewController, @@ -207,6 +209,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mFeatureFlags = featureFlags; mStatusBarIconController = statusBarIconController; mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager; + mDarkIconManagerFactory = darkIconManagerFactory; mKeyguardStateController = keyguardStateController; mNotificationPanelViewController = notificationPanelViewController; mNetworkController = networkController; @@ -247,7 +250,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mStatusBar.restoreHierarchyState( savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE)); } - mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons), mFeatureFlags); + mDarkIconManager = mDarkIconManagerFactory.create(view.findViewById(R.id.statusIcons)); mDarkIconManager.setShouldLog(true); updateBlockedIcons(); mStatusBarIconController.addIconGroup(mDarkIconManager); 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 6c02b0d44db3..000000000000 --- 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 8d69422c7427..000000000000 --- 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 1aae25058ba8..fe846747d0c6 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 android.content.Context 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.isNewPipelineBackendEnabled()) { + 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 f88e9d67d25d..000000000000 --- 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/StatusBarPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt index 589cdb8182cb..9b8b6434827e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt @@ -25,13 +25,28 @@ import javax.inject.Inject @SysUISingleton class StatusBarPipelineFlags @Inject constructor(private val featureFlags: FeatureFlags) { /** - * Returns true if we should run the new pipeline. + * Returns true if we should run the new pipeline backend. * - * TODO(b/238425913): We may want to split this out into: - * (1) isNewPipelineLoggingEnabled(), where the new pipeline runs and logs its decisions but - * doesn't change the UI at all. - * (2) isNewPipelineEnabled(), where the new pipeline runs and does change the UI (and the old - * pipeline doesn't change the UI). + * The new pipeline backend hooks up to all our external callbacks, logs those callback inputs, + * and logs the output state. */ - fun isNewPipelineEnabled(): Boolean = featureFlags.isEnabled(Flags.NEW_STATUS_BAR_PIPELINE) + fun isNewPipelineBackendEnabled(): Boolean = + featureFlags.isEnabled(Flags.NEW_STATUS_BAR_PIPELINE_BACKEND) + + /** + * Returns true if we should run the new pipeline frontend *and* backend. + * + * The new pipeline frontend will use the outputted state from the new backend and will make the + * correct changes to the UI. + */ + fun isNewPipelineFrontendEnabled(): Boolean = + isNewPipelineBackendEnabled() && + featureFlags.isEnabled(Flags.NEW_STATUS_BAR_PIPELINE_FRONTEND) + + /** + * Returns true if we should apply some coloring to icons that were rendered with the new + * pipeline to help with debugging. + */ + // For now, just always apply the debug coloring if we've enabled frontend rendering. + fun useNewPipelineDebugColoring(): Boolean = isNewPipelineFrontendEnabled() } 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 c4e2b732f388..88eccb5ba47f 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 class StatusBarPipelineModule { 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 e5980c3693ee..000000000000 --- 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 000000000000..2a89309f7200 --- /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 000000000000..44c04968041e --- /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 000000000000..5566fa6b5835 --- /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 000000000000..43fbabca823f --- /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 000000000000..a9da63b43aa4 --- /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 000000000000..a19d1bdd8e62 --- /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/binder/WifiViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt new file mode 100644 index 000000000000..b06aaf441f5a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt @@ -0,0 +1,67 @@ +/* + * 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.binder + +import android.content.res.ColorStateList +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.core.view.isVisible +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.R +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS +import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel +import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch + +/** + * Binds a wifi icon in the status bar to its view-model. + * + * To use this properly, users should maintain a one-to-one relationship between the [View] and the + * view-binding, binding each view only once. It is okay and expected for the same instance of the + * view-model to be reused for multiple view/view-binder bindings. + */ +@OptIn(InternalCoroutinesApi::class) +object WifiViewBinder { + /** Binds the view to the view-model, continuing to update the former based on the latter. */ + @JvmStatic + fun bind( + view: ViewGroup, + viewModel: WifiViewModel, + ) { + val iconView = view.requireViewById<ImageView>(R.id.wifi_signal) + + view.isVisible = true + iconView.isVisible = true + iconView.setImageDrawable(view.context.getDrawable(WIFI_FULL_ICONS[2])) + + view.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + viewModel.tint.collect { tint -> + iconView.imageTintList = ColorStateList.valueOf(tint) + } + } + } + } + + // TODO(b/238425913): Hook up to [viewModel] to render actual changes to the wifi icon. + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt new file mode 100644 index 000000000000..c14a897fffab --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt @@ -0,0 +1,93 @@ +/* + * 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.view + +import android.content.Context +import android.graphics.Rect +import android.util.AttributeSet +import android.view.LayoutInflater +import com.android.systemui.R +import com.android.systemui.statusbar.BaseStatusBarWifiView +import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON +import com.android.systemui.statusbar.pipeline.wifi.ui.binder.WifiViewBinder +import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel + +/** + * A new and more modern implementation of [com.android.systemui.statusbar.StatusBarWifiView] that + * is updated by [WifiViewBinder]. + */ +class ModernStatusBarWifiView( + context: Context, + attrs: AttributeSet? +) : BaseStatusBarWifiView(context, attrs) { + + private lateinit var slot: String + + override fun onDarkChanged(areas: ArrayList<Rect>?, darkIntensity: Float, tint: Int) { + // TODO(b/238425913) + } + + override fun getSlot() = slot + + override fun setStaticDrawableColor(color: Int) { + // TODO(b/238425913) + } + + override fun setDecorColor(color: Int) { + // TODO(b/238425913) + } + + override fun setVisibleState(state: Int, animate: Boolean) { + // TODO(b/238425913) + } + + override fun getVisibleState(): Int { + // TODO(b/238425913) + return STATE_ICON + } + + override fun isIconVisible(): Boolean { + // TODO(b/238425913) + return true + } + + /** Set the slot name for this view. */ + private fun setSlot(slotName: String) { + this.slot = slotName + } + + companion object { + /** + * Inflates a new instance of [ModernStatusBarWifiView], binds it to [viewModel], and + * returns it. + */ + @JvmStatic + fun constructAndBind( + context: Context, + slot: String, + viewModel: WifiViewModel, + ): ModernStatusBarWifiView { + return ( + LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null) + as ModernStatusBarWifiView + ).also { + it.setSlot(slot) + WifiViewBinder.bind(it, viewModel) + } + } + } +} 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 000000000000..7a262605681d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt @@ -0,0 +1,56 @@ +/* + * 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 android.graphics.Color +import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags +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.emptyFlow +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( + statusBarPipelineFlags: StatusBarPipelineFlags, + 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") + + /** The tint that should be applied to the icon. */ + val tint: Flow<Int> = if (!statusBarPipelineFlags.useNewPipelineDebugColoring()) { + emptyFlow() + } else { + flowOf(Color.CYAN) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java index 094490ba7adc..adef1823d491 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 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { 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 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { 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 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { } 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 8f2a432d0ba1..fc20ac241e38 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 @@ constructor( 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 345fc99f8a54..4dc78f9ec8a6 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; 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 @@ public class StorageNotification extends CoreStartable { } 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 @@ public class StorageNotification extends CoreStartable { 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/util/kotlin/IpcSerializer.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/IpcSerializer.kt new file mode 100644 index 000000000000..c0331e6000bf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/IpcSerializer.kt @@ -0,0 +1,98 @@ +/* + * 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.util.kotlin + +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.Job +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.runBlocking + +/** + * A utility for handling incoming IPCs from a Binder interface in the order that they are received. + * + * This class serves as a replacement for the common [android.os.Handler] message-queue pattern, + * where IPCs can arrive on arbitrary threads and are all enqueued onto a queue and processed by the + * Handler in-order. + * + * class MyService : Service() { + * + * private val serializer = IpcSerializer() + * + * // Need to invoke process() in order to actually process IPCs sent over the serializer. + * override fun onStart(...) = lifecycleScope.launch { + * serializer.process() + * } + * + * // In your binder implementation, use runSerializedBlocking to enqueue a function onto + * // the serializer. + * override fun onBind(intent: Intent?) = object : IAidlService.Stub() { + * override fun ipcMethodFoo() = serializer.runSerializedBlocking { + * ... + * } + * + * override fun ipcMethodBar() = serializer.runSerializedBlocking { + * ... + * } + * } + * } + */ +class IpcSerializer { + + private val channel = Channel<Pair<CompletableDeferred<Unit>, Job>>() + + /** + * Runs functions enqueued via usage of [runSerialized] and [runSerializedBlocking] serially. + * This method will never complete normally, so it must be launched in its own coroutine; if + * this is not actively running, no enqueued functions will be evaluated. + */ + suspend fun process(): Nothing { + for ((start, finish) in channel) { + // Signal to the sender that serializer has reached this message + start.complete(Unit) + // Wait to hear from the sender that it has finished running it's work, before handling + // the next message + finish.join() + } + error("Unexpected end of serialization channel") + } + + /** + * Enqueues [block] for evaluation by the serializer, suspending the caller until it has + * completed. It is up to the caller to define what thread this is evaluated in, determined + * by the [kotlin.coroutines.CoroutineContext] used. + */ + suspend fun <R> runSerialized(block: suspend () -> R): R { + val start = CompletableDeferred(Unit) + val finish = CompletableDeferred(Unit) + // Enqueue our message on the channel. + channel.send(start to finish) + // Wait for the serializer to reach our message + start.await() + // Now evaluate the block + val result = block() + // Notify the serializer that we've completed evaluation + finish.complete(Unit) + return result + } + + /** + * Enqueues [block] for evaluation by the serializer, blocking the binder thread until it has + * completed. Evaluation occurs on the binder thread, so methods like + * [android.os.Binder.getCallingUid] that depend on the current thread will work as expected. + */ + fun <R> runSerializedBlocking(block: suspend () -> R): R = runBlocking { runSerialized(block) } +} diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java index 4c762702892a..199048ec7b2e 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.RemoteException; 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; @@ -49,9 +50,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; -import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.dump.DumpManager; import com.android.systemui.model.SysUiState; import com.android.systemui.shade.ShadeController; import com.android.systemui.shared.system.QuickStepContract; @@ -76,7 +75,6 @@ import com.android.wm.shell.bubbles.Bubble; import com.android.wm.shell.bubbles.BubbleEntry; import com.android.wm.shell.bubbles.Bubbles; -import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -91,7 +89,7 @@ import java.util.function.IntConsumer; * The SysUi side bubbles manager which communicate with other SysUi components. */ @SysUISingleton -public class BubblesManager implements Dumpable { +public class BubblesManager { private static final String TAG = TAG_WITH_CLASS_NAME ? "BubblesManager" : TAG_BUBBLES; @@ -101,6 +99,7 @@ public class BubblesManager implements Dumpable { 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 +125,7 @@ public class BubblesManager implements Dumpable { ShadeController shadeController, @Nullable IStatusBarService statusBarService, INotificationManager notificationManager, + IDreamManager dreamManager, NotificationVisibilityProvider visibilityProvider, NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, @@ -134,7 +134,6 @@ public class BubblesManager implements Dumpable { CommonNotifCollection notifCollection, NotifPipeline notifPipeline, SysUiState sysUiState, - DumpManager dumpManager, Executor sysuiMainExecutor) { if (bubblesOptional.isPresent()) { return new BubblesManager(context, @@ -144,6 +143,7 @@ public class BubblesManager implements Dumpable { shadeController, statusBarService, notificationManager, + dreamManager, visibilityProvider, interruptionStateProvider, zenModeController, @@ -152,7 +152,6 @@ public class BubblesManager implements Dumpable { notifCollection, notifPipeline, sysUiState, - dumpManager, sysuiMainExecutor); } else { return null; @@ -167,6 +166,7 @@ public class BubblesManager implements Dumpable { ShadeController shadeController, @Nullable IStatusBarService statusBarService, INotificationManager notificationManager, + IDreamManager dreamManager, NotificationVisibilityProvider visibilityProvider, NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, @@ -175,13 +175,13 @@ public class BubblesManager implements Dumpable { CommonNotifCollection notifCollection, NotifPipeline notifPipeline, SysUiState sysUiState, - DumpManager dumpManager, Executor sysuiMainExecutor) { mContext = context; mBubbles = bubbles; mNotificationShadeWindowController = notificationShadeWindowController; mShadeController = shadeController; mNotificationManager = notificationManager; + mDreamManager = dreamManager; mVisibilityProvider = visibilityProvider; mNotificationInterruptStateProvider = interruptionStateProvider; mNotifUserManager = notifUserManager; @@ -197,13 +197,11 @@ public class BubblesManager implements Dumpable { setupNotifPipeline(); - dumpManager.registerDumpable(TAG, this); - keyguardStateController.addCallback(new KeyguardStateController.Callback() { @Override public void onKeyguardShowingChanged() { boolean isUnlockedShade = !keyguardStateController.isShowing() - && !keyguardStateController.isOccluded(); + && !isDreamingOrInPreview(); bubbles.onStatusBarStateChanged(isUnlockedShade); } }); @@ -397,6 +395,15 @@ public class BubblesManager implements Dumpable { 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 @@ -633,11 +640,6 @@ public class BubblesManager implements Dumpable { } } - @Override - public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { - mBubbles.dump(pw, args); - } - /** Checks whether bubbles are enabled for this user, handles negative userIds. */ public static boolean areBubblesEnabled(@NonNull Context context, @NonNull UserHandle user) { if (user.getIdentifier() < 0) { diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index eba279587629..a4a59fc9d4a7 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -29,14 +29,16 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_S import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; import android.content.Context; +import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.inputmethodservice.InputMethodService; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.view.KeyEvent; +import androidx.annotation.NonNull; + import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; @@ -47,11 +49,11 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.model.SysUiState; +import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.tracing.ProtoTraceable; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.tracing.ProtoTracer; import com.android.systemui.tracing.nano.SystemUiTraceProto; import com.android.wm.shell.nano.WmShellTraceProto; @@ -66,6 +68,7 @@ import com.android.wm.shell.sysui.ShellInterface; import java.io.PrintWriter; import java.util.Arrays; +import java.util.List; import java.util.Optional; import java.util.concurrent.Executor; @@ -115,7 +118,7 @@ public final class WMShell extends CoreStartable private final SysUiState mSysUiState; private final WakefulnessLifecycle mWakefulnessLifecycle; private final ProtoTracer mProtoTracer; - private final UserInfoController mUserInfoController; + private final UserTracker mUserTracker; private final Executor mSysUiMainExecutor; // Listeners and callbacks. Note that we prefer member variable over anonymous class here to @@ -144,9 +147,20 @@ public final class WMShell extends CoreStartable mShell.onKeyguardDismissAnimationFinished(); } }; + private final UserTracker.Callback mUserChangedCallback = + new UserTracker.Callback() { + @Override + public void onUserChanged(int newUser, @NonNull Context userContext) { + mShell.onUserChanged(newUser, userContext); + } + + @Override + public void onProfilesChanged(@NonNull List<UserInfo> profiles) { + mShell.onUserProfilesChanged(profiles); + } + }; private boolean mIsSysUiStateValid; - private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback; private WakefulnessLifecycle.Observer mWakefulnessObserver; @Inject @@ -163,7 +177,7 @@ public final class WMShell extends CoreStartable SysUiState sysUiState, ProtoTracer protoTracer, WakefulnessLifecycle wakefulnessLifecycle, - UserInfoController userInfoController, + UserTracker userTracker, @Main Executor sysUiMainExecutor) { super(context); mShell = shell; @@ -178,7 +192,7 @@ public final class WMShell extends CoreStartable mOneHandedOptional = oneHandedOptional; mWakefulnessLifecycle = wakefulnessLifecycle; mProtoTracer = protoTracer; - mUserInfoController = userInfoController; + mUserTracker = userTracker; mSysUiMainExecutor = sysUiMainExecutor; } @@ -192,8 +206,9 @@ public final class WMShell extends CoreStartable mKeyguardStateController.addCallback(mKeyguardStateCallback); mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); - // TODO: Consider piping config change and other common calls to a shell component to - // delegate internally + // Subscribe to user changes + mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor()); + mProtoTracer.add(this); mCommandQueue.addCallback(this); mPipOptional.ifPresent(this::initPip); @@ -214,10 +229,6 @@ public final class WMShell extends CoreStartable mIsSysUiStateValid = (sysUiStateFlag & INVALID_SYSUI_STATE_MASK) == 0; pip.onSystemUiStateChanged(mIsSysUiStateValid, sysUiStateFlag); }); - - // The media session listener needs to be re-registered when switching users - mUserInfoController.addCallback((String name, Drawable picture, String userAccount) -> - pip.registerSessionListenerForCurrentUser()); } @VisibleForTesting @@ -267,15 +278,6 @@ public final class WMShell extends CoreStartable } }); - // TODO: Either move into ShellInterface or register a receiver on the Shell side directly - mOneHandedKeyguardCallback = new KeyguardUpdateMonitorCallback() { - @Override - public void onUserSwitchComplete(int userId) { - oneHanded.onUserSwitch(userId); - } - }; - mKeyguardUpdateMonitor.registerCallback(mOneHandedKeyguardCallback); - mWakefulnessObserver = new WakefulnessLifecycle.Observer() { @Override diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index 763a5cb810f9..ba2804572ef5 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 01309f86a137..7f6b79b48939 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 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { } @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 141a213a5b6a..b42b7695cedd 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.AndroidTestingRunner; 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 com.android.systemui.util.settings.SecureSettings; 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 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { @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 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { } @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 19491f41a0c1..14b85b8b5e56 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.statusbar.policy.KeyguardStateController 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 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { val testConfig = TestConfig( isVisible = true, + isClickable = true, icon = mock(), canShowWhileLocked = false, intent = Intent("action"), @@ -154,6 +157,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { 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 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { val testConfig = TestConfig( isVisible = true, + isClickable = true, icon = mock(), canShowWhileLocked = false, intent = Intent("action"), @@ -260,6 +265,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { testConfig = TestConfig( isVisible = true, + isClickable = true, icon = mock(), canShowWhileLocked = true, ) @@ -269,6 +275,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { testConfig = TestConfig( isVisible = true, + isClickable = true, icon = mock(), canShowWhileLocked = false, ) @@ -342,6 +349,129 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { 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 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { ) { 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 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { 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 000000000000..373af5cdf4b7 --- /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 80f3e46b848f..91a6de6ae4c0 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 @@ package com.android.systemui.lifecycle 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 kotlinx.coroutines.test.runBlockingTest 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 @@ class RepeatWhenAttachedTest : SysuiTestCase() { _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 fcfef4a44128..c41fac71a179 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.Test 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 @@ class KeyguardMediaControllerTest : SysuiTestCase() { @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 @@ class KeyguardMediaControllerTest : SysuiTestCase() { } @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 @@ class KeyguardMediaControllerTest : SysuiTestCase() { } @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 1cce7cfb5b8a..d1ed8e983cdd 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.Mock 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 @@ class MediaDataManagerTest : SysuiTestCase() { } @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 369913d1ea73..18bfd04102b7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.media import android.graphics.Rect +import android.provider.Settings import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.ViewGroup @@ -30,7 +31,6 @@ import com.android.systemui.dreams.DreamOverlayStateController import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.shade.testing.FakeNotifPanelEvents -import com.android.systemui.statusbar.NotificationLockscreenUserManager 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.FakeConfigurationController 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 @@ -53,7 +55,6 @@ import org.mockito.Mock import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.times import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit @@ -68,7 +69,6 @@ class MediaHierarchyManagerTest : SysuiTestCase() { @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 @@ -82,37 +82,42 @@ class MediaHierarchyManagerTest : SysuiTestCase() { @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, 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) @@ -122,30 +127,30 @@ class MediaHierarchyManagerTest : SysuiTestCase() { } 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()) @@ -154,13 +159,13 @@ class MediaHierarchyManagerTest : SysuiTestCase() { @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()) } @@ -170,7 +175,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { 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), @@ -180,7 +185,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { 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), @@ -189,7 +194,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { anyLong()) // Let's make sure alpha is set - mediaHiearchyManager.setTransitionToFullShadeAmount(2.0f) + mediaHierarchyManager.setTransitionToFullShadeAmount(2.0f) assertThat(mediaFrame.alpha).isNotEqualTo(1.0f) } @@ -198,7 +203,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { goToLockscreen() expandQS() - val transformType = mediaHiearchyManager.calculateTransformationType() + val transformType = mediaHierarchyManager.calculateTransformationType() assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) } @@ -206,7 +211,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { fun calculateTransformationType_notOnLockscreen_returnsTransition() { expandQS() - val transformType = mediaHiearchyManager.calculateTransformationType() + val transformType = mediaHierarchyManager.calculateTransformationType() assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION) } @@ -216,7 +221,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { goToLockscreen() expandQS() - val transformType = mediaHiearchyManager.calculateTransformationType() + val transformType = mediaHierarchyManager.calculateTransformationType() assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) } @@ -226,9 +231,9 @@ class MediaHierarchyManagerTest : SysuiTestCase() { enableSplitShade() goToLockscreen() expandQS() - mediaHiearchyManager.setTransitionToFullShadeAmount(10000f) + mediaHierarchyManager.setTransitionToFullShadeAmount(10000f) - val transformType = mediaHiearchyManager.calculateTransformationType() + val transformType = mediaHierarchyManager.calculateTransformationType() assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION) } @@ -238,9 +243,9 @@ class MediaHierarchyManagerTest : SysuiTestCase() { 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) } @@ -250,9 +255,9 @@ class MediaHierarchyManagerTest : SysuiTestCase() { goToLockscreen() goToLockedShade() expandQS() - mediaHiearchyManager.setTransitionToFullShadeAmount(0f) + mediaHierarchyManager.setTransitionToFullShadeAmount(0f) - val transformType = mediaHiearchyManager.calculateTransformationType() + val transformType = mediaHierarchyManager.calculateTransformationType() assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) } @@ -261,13 +266,13 @@ class MediaHierarchyManagerTest : SysuiTestCase() { 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() } @@ -281,7 +286,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { @Test fun getGuidedTransformationTranslationY_notInGuidedTransformation_returnsNegativeNumber() { - assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY()).isLessThan(0) + assertThat(mediaHierarchyManager.getGuidedTransformationTranslationY()).isLessThan(0) } @Test @@ -289,7 +294,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { enterGuidedTransformation() val expectedTranslation = LOCKSCREEN_TOP - QS_TOP - assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY()) + assertThat(mediaHierarchyManager.getGuidedTransformationTranslationY()) .isEqualTo(expectedTranslation) } @@ -301,7 +306,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { whenever(qsHost.visible).thenReturn(true) whenever(qqsHost.visible).thenReturn(true) - assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isTrue() + assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isTrue() } @Test @@ -313,7 +318,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { whenever(qsHost.visible).thenReturn(true) whenever(qqsHost.visible).thenReturn(true) - assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isFalse() + assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse() } @Test @@ -324,7 +329,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { whenever(qsHost.visible).thenReturn(true) whenever(qqsHost.visible).thenReturn(true) - assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isFalse() + assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse() } private fun enableSplitShade() { @@ -336,9 +341,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { 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) } @@ -352,13 +355,13 @@ class MediaHierarchyManagerTest : SysuiTestCase() { } 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 2aab9e82986e..1131a7eb379a 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.never; 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 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase { 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 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase { 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 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase { } @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 751c8951859c..6dcf8024eca8 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.spy; 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.os.RemoteException; 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.LocalMediaManager; 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 @@ public class MediaOutputControllerTest extends SysuiTestCase { 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 @@ public class MediaOutputControllerTest extends SysuiTestCase { 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 @@ public class MediaOutputControllerTest extends SysuiTestCase { 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 @@ public class MediaOutputControllerTest extends SysuiTestCase { 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 @@ public class MediaOutputControllerTest extends SysuiTestCase { 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 @@ public class MediaOutputControllerTest extends SysuiTestCase { 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 4779d322a90e..9557513775f8 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.times; 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 @@ public class MediaOutputDialogTest extends SysuiTestCase { 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 @@ public class MediaOutputDialogTest extends SysuiTestCase { 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 247316a32473..c101b9ffd495 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 androidx.test.filters.SmallTest; 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 @@ public class MediaDreamSentinelTest extends SysuiTestCase { @Mock MediaDreamComplication mComplication; + @Mock + FeatureFlags mFeatureFlags; + final String mKey = "key"; final String mOldKey = "old_key"; @@ -59,21 +65,18 @@ public class MediaDreamSentinelTest extends SysuiTestCase { @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 @@ public class MediaDreamSentinelTest extends SysuiTestCase { 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/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt index be14cc51ef96..cb4f08e6c552 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt @@ -93,6 +93,10 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { private lateinit var featureFlags: FeatureFlags @Mock private lateinit var insetsProvider: StatusBarContentInsetsProvider + @Mock + private lateinit var iconManagerFactory: StatusBarIconController.TintedIconManager.Factory + @Mock + private lateinit var iconManager: StatusBarIconController.TintedIconManager private val qsExpansionPathInterpolator = QSExpansionPathInterpolator() @@ -106,6 +110,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { `when`(qsCarrierGroupControllerBuilder.build()).thenReturn(qsCarrierGroupController) `when`(variableDateViewControllerFactory.create(any())) .thenReturn(variableDateViewController) + `when`(iconManagerFactory.create(any())).thenReturn(iconManager) `when`(view.resources).thenReturn(mContext.resources) `when`(view.isAttachedToWindow).thenReturn(true) `when`(view.context).thenReturn(context) @@ -122,7 +127,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() { featureFlags, variableDateViewControllerFactory, batteryMeterViewController, - insetsProvider + insetsProvider, + iconManagerFactory, ) } 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 000000000000..447e28cd9527 --- /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 000000000000..28d53c72640f --- /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 ce3f20d4d39d..00f38081c5c9 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 android.view.SurfaceControl.ScreenshotHardwareBuffer 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 @@ import org.junit.runner.RunWith 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 ImageCaptureImplTest : SysuiTestCase() { 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 @@ class ImageCaptureImplTest : SysuiTestCase() { 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 024d3bd8eb0e..48fbd354b98d 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.ColorSpace 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 testProcessAsync() { + flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false) + + val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD) + val processor = RequestProcessor(imageCapture, policy, flags, scope) + + var result: ScreenshotRequest? = null + var callbackCount = 0 + val callback: (ScreenshotRequest) -> Unit = { processedRequest: ScreenshotRequest -> + result = processedRequest + callbackCount++ + } + + // 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 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() { + 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 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).takeScreenshotFullscreen(/* topComponent */ isNull(), - eq(onSavedListener), eq(callback)) + // Request has topComponent added, but otherwise unchanged. + assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_FULLSCREEN) + assertThat(processedRequest.topComponent).isEqualTo(component) } @Test - fun testSelectedRegionScreenshot() { + 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 processor = RequestProcessor(imageCapture, policy, flags, scope) + + val processedRequest = processor.process(request) + + // 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 onSavedListener = mock<Consumer<Uri>>() - val callback = mock<RequestCallback>() - val processor = RequestProcessor(controller) + val processor = RequestProcessor(imageCapture, policy, flags, scope) - processor.processRequest(request, onSavedListener, callback) + policy.setManagedProfile(USER_ID, false) + policy.setDisplayContentInfo(policy.getDefaultDisplayId(), + DisplayContentInfo(component, bounds, USER_ID, TASK_ID)) - verify(controller).takeScreenshotPartial(/* topComponent */ isNull(), - eq(onSavedListener), eq(callback)) + 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 testSelectedRegionScreenshot_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 + + 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() { - val taskId = 1111 - val userId = 2222 + fun testProvidedImageScreenshot_workProfilePolicyDisabled() = runBlocking { + flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false) + val bounds = Rect(50, 50, 150, 150) - val topComponent = ComponentName("test", "test") - val processor = RequestProcessor(controller) + val processor = RequestProcessor(imageCapture, policy, flags, scope) - 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))!! + 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) + // No changes + assertThat(processedRequest).isEqualTo(request) + } + + @Test + fun testProvidedImageScreenshot() = runBlocking { + flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true) - verify(controller).handleImageAsScreenshot( - bitmapCaptor.capture(), eq(bounds), eq(Insets.NONE), eq(taskId), eq(userId), - eq(topComponent), eq(onSavedListener), eq(callback) - ) + 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) - assertThat(bitmapCaptor.value.equalsHardwareBitmap(bitmap)).isTrue() + 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.equalsHardwareBitmap(bitmap: Bitmap): Boolean { - return bitmap.hardwareBuffer == this.hardwareBuffer && - bitmap.colorSpace == this.colorSpace + 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/LargeScreenShadeHeaderControllerCombinedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt index ed1a13b36d6c..20c6d9adc300 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt @@ -91,6 +91,10 @@ class LargeScreenShadeHeaderControllerCombinedTest : SysuiTestCase() { @Mock private lateinit var statusBarIconController: StatusBarIconController @Mock + private lateinit var iconManagerFactory: StatusBarIconController.TintedIconManager.Factory + @Mock + private lateinit var iconManager: StatusBarIconController.TintedIconManager + @Mock private lateinit var qsCarrierGroupController: QSCarrierGroupController @Mock private lateinit var qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder @@ -169,6 +173,8 @@ class LargeScreenShadeHeaderControllerCombinedTest : SysuiTestCase() { } whenever(view.visibility).thenAnswer { _ -> viewVisibility } + whenever(iconManagerFactory.create(any())).thenReturn(iconManager) + whenever(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)).thenReturn(true) whenever(featureFlags.isEnabled(Flags.NEW_HEADER)).thenReturn(true) @@ -178,6 +184,7 @@ class LargeScreenShadeHeaderControllerCombinedTest : SysuiTestCase() { controller = LargeScreenShadeHeaderController( view, statusBarIconController, + iconManagerFactory, privacyIconsController, insetsProvider, configurationController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt index 02b26dbbc32d..eeb61bc8a0f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt @@ -43,6 +43,8 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() { @Mock private lateinit var view: View @Mock private lateinit var statusIcons: StatusIconContainer @Mock private lateinit var statusBarIconController: StatusBarIconController + @Mock private lateinit var iconManagerFactory: StatusBarIconController.TintedIconManager.Factory + @Mock private lateinit var iconManager: StatusBarIconController.TintedIconManager @Mock private lateinit var qsCarrierGroupController: QSCarrierGroupController @Mock private lateinit var qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder @Mock private lateinit var featureFlags: FeatureFlags @@ -91,10 +93,12 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() { whenever(view.visibility).thenAnswer { _ -> viewVisibility } whenever(variableDateViewControllerFactory.create(any())) .thenReturn(variableDateViewController) + whenever(iconManagerFactory.create(any())).thenReturn(iconManager) whenever(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)).thenReturn(false) mLargeScreenShadeHeaderController = LargeScreenShadeHeaderController( view, statusBarIconController, + iconManagerFactory, privacyIconsController, insetsProvider, configurationController, 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 30ab424b25d2..7d28871e340c 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.ContentResolver; 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 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { @Mock private DozeLog mDozeLog; @Mock + private ShadeLogger mShadeLog; + @Mock private CommandQueue mCommandQueue; @Mock private VibratorHelper mVibratorHelper; @@ -524,7 +525,9 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { mNotificationShadeWindowController, mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper, mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor, - mMetricsLogger, mConfigurationController, + mMetricsLogger, + mShadeLog, + mConfigurationController, () -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager, mConversationNotificationManager, mMediaHiearchyManager, mStatusBarKeyguardViewManager, @@ -760,10 +763,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { @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); } @@ -1216,7 +1217,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); clearInvocations(mKeyguardStatusViewController); - mNotificationPanelViewController.setDozing(/* dozing= */ true, /* animate= */ false, null); + mNotificationPanelViewController.setDozing(/* dozing= */ true, /* animate= */ false); verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate= */ true); } @@ -1230,7 +1231,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); clearInvocations(mKeyguardStatusViewController); - mNotificationPanelViewController.setDozing(/* dozing= */ true, /* animate= */ false, null); + mNotificationPanelViewController.setDozing(/* dozing= */ true, /* animate= */ false); verify(mKeyguardStatusViewController).displayClock(SMALL, /* animate= */ true); } @@ -1244,7 +1245,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { 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); } @@ -1558,8 +1559,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mDozeParameters.getAlwaysOn()).thenReturn(dozingAlwaysOn); mNotificationPanelViewController.setDozing( /* dozing= */ dozing, - /* animate= */ false, - /* wakeUpTouchLocation= */ new PointF() + /* animate= */ false ); } 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 000000000000..9393a4f4eead --- /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 be631afdd1a9..1d8e5dec5c50 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.ArgumentMatchers.eq 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 @@ class StatusBarStateControllerImplTest : SysuiTestCase() { 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 @@ class StatusBarStateControllerImplTest : SysuiTestCase() { @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/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt index 20747a05a360..790865bb496f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt @@ -56,6 +56,7 @@ import com.android.systemui.util.mockito.eq import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.time.FakeSystemClock import java.util.Optional +import java.util.concurrent.Executor import org.junit.Before import org.junit.Test import org.mockito.ArgumentCaptor @@ -105,6 +106,9 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock + private lateinit var bgExecutor: Executor + + @Mock private lateinit var handler: Handler @Mock @@ -203,6 +207,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { keyguardBypassController, execution, executor, + bgExecutor, handler, Optional.of(plugin) ) 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 64d025628754..214ba16dfc44 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 @@ class ChannelEditorDialogControllerTest : SysuiTestCase() { @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/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java index 11e502fc79bf..6cf1a12d94f0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java @@ -47,7 +47,6 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.battery.BatteryMeterViewController; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.NotificationPanelViewController; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -89,7 +88,9 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { @Mock private StatusBarIconController mStatusBarIconController; @Mock - private FeatureFlags mFeatureFlags; + private StatusBarIconController.TintedIconManager.Factory mIconManagerFactory; + @Mock + private StatusBarIconController.TintedIconManager mIconManager; @Mock private BatteryMeterViewController mBatteryMeterViewController; @Mock @@ -129,6 +130,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); + when(mIconManagerFactory.create(any())).thenReturn(mIconManager); + allowTestableLooperAsMainThread(); TestableLooper.get(this).runWithLooper(() -> { mKeyguardStatusBarView = @@ -148,7 +151,7 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { mBatteryController, mUserInfoController, mStatusBarIconController, - new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags), + mIconManagerFactory, mBatteryMeterViewController, mNotificationPanelViewStateProvider, mKeyguardStateController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java index 0f1c40bacb7b..a6b7e5103c78 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java @@ -40,12 +40,16 @@ import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconMana import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; +import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags; +import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel; import com.android.systemui.utils.leaks.LeakCheckedTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import javax.inject.Provider; + @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest @@ -67,7 +71,11 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { @Test public void testSetCalledOnAdd_DarkIconManager() { LinearLayout layout = new LinearLayout(mContext); - TestDarkIconManager manager = new TestDarkIconManager(layout, mock(FeatureFlags.class)); + TestDarkIconManager manager = new TestDarkIconManager( + layout, + mock(FeatureFlags.class), + mock(StatusBarPipelineFlags.class), + () -> mock(WifiViewModel.class)); testCallOnAdd_forManager(manager); } @@ -104,8 +112,12 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { private static class TestDarkIconManager extends DarkIconManager implements TestableIconManager { - TestDarkIconManager(LinearLayout group, FeatureFlags featureFlags) { - super(group, featureFlags); + TestDarkIconManager( + LinearLayout group, + FeatureFlags featureFlags, + StatusBarPipelineFlags statusBarPipelineFlags, + Provider<WifiViewModel> wifiViewModelProvider) { + super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider); } @Override @@ -123,7 +135,7 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { } @Override - protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) { + protected StatusBarWifiView addWifiIcon(int index, String slot, WifiIconState state) { StatusBarWifiView mock = mock(StatusBarWifiView.class); mGroup.addView(mock, index); return mock; @@ -140,7 +152,10 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { private static class TestIconManager extends IconManager implements TestableIconManager { TestIconManager(ViewGroup group) { - super(group, mock(FeatureFlags.class)); + super(group, + mock(FeatureFlags.class), + mock(StatusBarPipelineFlags.class), + () -> mock(WifiViewModel.class)); } @Override @@ -158,7 +173,7 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { } @Override - protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) { + protected StatusBarWifiView addWifiIcon(int index, String slot, WifiIconState state) { StatusBarWifiView mock = mock(StatusBarWifiView.class); mGroup.addView(mock, index); return mock; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java index 52a573f24afb..20bf50e41f49 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java @@ -113,6 +113,10 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { @Mock private NotificationPanelViewController mNotificationPanelViewController; @Mock + private StatusBarIconController.DarkIconManager.Factory mIconManagerFactory; + @Mock + private StatusBarIconController.DarkIconManager mIconManager; + @Mock private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; @Mock private DumpManager mDumpManager; @@ -463,6 +467,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class); when(mOperatorNameViewControllerFactory.create(any())) .thenReturn(mOperatorNameViewController); + when(mIconManagerFactory.create(any())).thenReturn(mIconManager); mSecureSettings = mock(SecureSettings.class); setUpNotificationIconAreaController(); @@ -475,6 +480,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { new PanelExpansionStateManager(), mock(FeatureFlags.class), mStatusBarIconController, + mIconManagerFactory, mStatusBarHideIconsForBouncerManager, mKeyguardStateController, mNotificationPanelViewController, 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 515a7c936f4d..000000000000 --- 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/repository/NetworkCapabilitiesRepoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/repository/NetworkCapabilitiesRepoTest.kt deleted file mode 100644 index 40f8fbfd9af2..000000000000 --- 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 index 2915ae8dea88..36be1be309d6 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 000000000000..6b8d4aa7c51f --- /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 000000000000..d0a38084af76 --- /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 000000000000..5f1b1dbb19dc --- /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/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt new file mode 100644 index 000000000000..3c200a5da4fa --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.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.ui.view + +import android.testing.TestableLooper.RunWithLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.lifecycle.InstantTaskExecutorRule +import com.android.systemui.util.Assert +import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@SmallTest +@RunWith(JUnit4::class) +@RunWithLooper +class ModernStatusBarWifiViewTest : SysuiTestCase() { + + @JvmField @Rule + val instantTaskExecutor = InstantTaskExecutorRule() + + @Before + fun setUp() { + Assert.setTestThread(Thread.currentThread()) + } + + @Test + fun constructAndBind_hasCorrectSlot() { + val view = ModernStatusBarWifiView.constructAndBind( + context, "slotName", mock() + ) + + assertThat(view.slot).isEqualTo("slotName") + } +} 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 000000000000..c79073409883 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt @@ -0,0 +1,127 @@ +/* + * 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.StatusBarPipelineFlags +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 statusBarPipelineFlags: StatusBarPipelineFlags + @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( + statusBarPipelineFlags, + 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 b7f38f1433ff..50259b5246f5 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 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { } @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 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { } @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 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { } @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 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { 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 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { } @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/util/kotlin/IpcSerializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt new file mode 100644 index 000000000000..15ba67205034 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt @@ -0,0 +1,71 @@ +/* + * 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.util.kotlin + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import java.util.concurrent.atomic.AtomicLong +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class IpcSerializerTest : SysuiTestCase() { + + private val serializer = IpcSerializer() + + @Test + fun serializeManyIncomingIpcs(): Unit = runBlocking(Dispatchers.Main.immediate) { + val processor = launch(start = CoroutineStart.LAZY) { serializer.process() } + withContext(Dispatchers.IO) { + val lastEvaluatedTime = AtomicLong(System.currentTimeMillis()) + // First, launch many serialization requests in parallel + repeat(100_000) { + launch(Dispatchers.Unconfined) { + val enqueuedTime = System.currentTimeMillis() + serializer.runSerialized { + val last = lastEvaluatedTime.getAndSet(enqueuedTime) + assertTrue( + "expected $last less than or equal to $enqueuedTime ", + last <= enqueuedTime, + ) + } + } + } + // Then, process them all in the order they came in. + processor.start() + } + // All done, stop processing + processor.cancel() + } + + @Test(timeout = 5000) + fun serializeOnOneThread_doesNotDeadlock() = runBlocking { + val job = launch { serializer.process() } + repeat(100) { + serializer.runSerializedBlocking { } + } + job.cancel() + } +} 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 18acf3f6ce53..5d63632725c2 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.graphics.drawable.Icon; 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; @@ -134,6 +135,7 @@ import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.onehanded.OneHandedController; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; @@ -204,6 +206,8 @@ public class BubblesTest extends SysuiTestCase { private ArgumentCaptor<IntentFilter> mFilterArgumentCaptor; @Captor private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor; + @Captor + private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallbackCaptor; private BubblesManager mBubblesManager; private TestableBubbleController mBubbleController; @@ -222,6 +226,8 @@ public class BubblesTest extends SysuiTestCase { @Mock private ShellInit mShellInit; @Mock + private ShellCommandHandler mShellCommandHandler; + @Mock private ShellController mShellController; @Mock private Bubbles.BubbleExpandListener mBubbleExpandListener; @@ -240,6 +246,8 @@ public class BubblesTest extends SysuiTestCase { @Mock private IStatusBarService mStatusBarService; @Mock + private IDreamManager mIDreamManager; + @Mock private NotificationVisibilityProvider mVisibilityProvider; @Mock private LauncherApps mLauncherApps; @@ -344,6 +352,7 @@ public class BubblesTest extends SysuiTestCase { mBubbleController = new TestableBubbleController( mContext, mShellInit, + mShellCommandHandler, mShellController, mBubbleData, mFloatingContentCoordinator, @@ -371,10 +380,11 @@ public class BubblesTest extends SysuiTestCase { mContext, mBubbleController.asBubbles(), mNotificationShadeWindowController, - mock(KeyguardStateController.class), + mKeyguardStateController, mShadeController, mStatusBarService, mock(INotificationManager.class), + mIDreamManager, mVisibilityProvider, interruptionStateProvider, mZenModeController, @@ -383,7 +393,6 @@ public class BubblesTest extends SysuiTestCase { mCommonNotifCollection, mNotifPipeline, mSysUiState, - mDumpManager, syncExecutor); mBubblesManager.addNotifCallback(mNotifCallback); @@ -391,6 +400,25 @@ public class BubblesTest extends SysuiTestCase { 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 @@ -1370,6 +1398,33 @@ public class BubblesTest extends SysuiTestCase { assertThat(stackView.getVisibility()).isEqualTo(View.VISIBLE); } + /** + * Test to verify behavior for following situation: + * <ul> + * <li>status bar shade state is set to <code>false</code></li> + * <li>there is a bubble pending to be expanded</li> + * </ul> + * Test that duplicate status bar state updates to <code>false</code> do not clear the + * pending bubble to be + * expanded. + */ + @Test + public void testOnStatusBarStateChanged_statusBarChangeDoesNotClearExpandingBubble() { + mBubbleController.updateBubble(mBubbleEntry); + mBubbleController.onStatusBarStateChanged(false); + // Set the bubble to expand once status bar state changes + mBubbleController.expandStackAndSelectBubble(mBubbleEntry); + // Check that stack is currently collapsed + assertStackCollapsed(); + // Post status bar state change update with the same value + mBubbleController.onStatusBarStateChanged(false); + // Stack should remain collapsedb + assertStackCollapsed(); + // Post status bar state change which should trigger bubble to expand + mBubbleController.onStatusBarStateChanged(true); + assertStackExpanded(); + } + @Test public void testSetShouldAutoExpand_notifiesFlagChanged() { mBubbleController.updateBubble(mBubbleEntry); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java index 880ad187f910..6357a09eb196 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java @@ -38,6 +38,7 @@ import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.onehanded.OneHandedController; +import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; @@ -51,6 +52,7 @@ public class TestableBubbleController extends BubbleController { // Let's assume surfaces can be synchronized immediately. TestableBubbleController(Context context, ShellInit shellInit, + ShellCommandHandler shellCommandHandler, ShellController shellController, BubbleData data, FloatingContentCoordinator floatingContentCoordinator, @@ -71,12 +73,12 @@ public class TestableBubbleController extends BubbleController { Handler shellMainHandler, TaskViewTransitions taskViewTransitions, SyncTransactionQueue syncQueue) { - super(context, shellInit, shellController, data, Runnable::run, floatingContentCoordinator, - dataRepository, statusBarService, windowManager, windowManagerShellWrapper, - userManager, launcherApps, bubbleLogger, taskStackListener, shellTaskOrganizer, - positioner, displayController, oneHandedOptional, dragAndDropController, - shellMainExecutor, shellMainHandler, new SyncExecutor(), taskViewTransitions, - syncQueue); + super(context, shellInit, shellCommandHandler, shellController, data, Runnable::run, + floatingContentCoordinator, dataRepository, statusBarService, windowManager, + windowManagerShellWrapper, userManager, launcherApps, bubbleLogger, + taskStackListener, shellTaskOrganizer, positioner, displayController, + oneHandedOptional, dragAndDropController, shellMainExecutor, shellMainHandler, + new SyncExecutor(), taskViewTransitions, syncQueue); setInflateSynchronously(true); onInit(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java index 9c2136675dfa..da33fa62a9ab 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java @@ -28,10 +28,10 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.model.SysUiState; +import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.tracing.ProtoTracer; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.onehanded.OneHanded; @@ -72,7 +72,7 @@ public class WMShellTest extends SysuiTestCase { @Mock OneHanded mOneHanded; @Mock WakefulnessLifecycle mWakefulnessLifecycle; @Mock ProtoTracer mProtoTracer; - @Mock UserInfoController mUserInfoController; + @Mock UserTracker mUserTracker; @Mock ShellExecutor mSysUiMainExecutor; @Before @@ -83,7 +83,7 @@ public class WMShellTest extends SysuiTestCase { Optional.of(mSplitScreen), Optional.of(mOneHanded), mCommandQueue, mConfigurationController, mKeyguardStateController, mKeyguardUpdateMonitor, mScreenLifecycle, mSysUiState, mProtoTracer, mWakefulnessLifecycle, - mUserInfoController, mSysUiMainExecutor); + mUserTracker, mSysUiMainExecutor); } @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 309acdf13a5d..f539dbdf76a0 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 @@ class KotlinArgumentCaptor<T> constructor(clazz: Class<T>) { 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 0a4ecb227548..5154a2ddd2cd 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -298,6 +298,10 @@ message SystemMessage { // 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/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index 43e2b881927c..593a63c2f0c9 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 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController 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 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController 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 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController * @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 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @ActivityPolicy int defaultActivityPolicy, @NonNull ActivityListener activityListener, @NonNull ActivityBlockedCallback activityBlockedCallback, + @NonNull SecureWindowCallback secureWindowCallback, @AssociationRequest.DeviceProfile String deviceProfile) { super(); mAllowedUsers = allowedUsers; @@ -154,6 +166,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController setInterestedWindowFlags(windowFlags, systemWindowFlags); mActivityListener = activityListener; mDeviceProfile = deviceProfile; + mSecureWindowCallback = secureWindowCallback; } /** @@ -234,6 +247,12 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @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 5f337ab9bae3..cca3212703f0 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.VirtualMouseScrollEvent; 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 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub mParams.getDefaultActivityPolicy(), createListenerAdapter(), this::onActivityBlocked, + this::onSecureWindowShown, mAssociationInfo.getDeviceProfile()); gwpc.registerRunningAppsChangedListener(/* listener= */ this); return gwpc; @@ -591,6 +593,21 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub 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 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub /** * 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 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub 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 35e9060b58d4..41b6fade4ac6 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 @@ public class VirtualDeviceManagerService extends SystemService { 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 b512cdfb6683..147b5507346c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -452,6 +452,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; @@ -5494,7 +5495,7 @@ public class ActivityManagerService extends IActivityManager.Stub IIntentSender pendingResult, int matchFlags) { enforceCallingPermission(Manifest.permission.GET_INTENT_SENDER_INTENT, "queryIntentComponentsForIntentSender()"); - Preconditions.checkNotNull(pendingResult); + Objects.requireNonNull(pendingResult); final PendingIntentRecord res; try { res = (PendingIntentRecord) pendingResult; @@ -5506,17 +5507,19 @@ public class ActivityManagerService extends IActivityManager.Stub return null; } final int userId = res.key.userId; + final int uid = res.uid; + final String resolvedType = res.key.requestResolvedType; switch (res.key.type) { case ActivityManager.INTENT_SENDER_ACTIVITY: - return new ParceledListSlice<>(mContext.getPackageManager() - .queryIntentActivitiesAsUser(intent, matchFlags, userId)); + return new ParceledListSlice<>(mPackageManagerInt.queryIntentActivities( + intent, resolvedType, matchFlags, uid, userId)); case ActivityManager.INTENT_SENDER_SERVICE: case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE: - return new ParceledListSlice<>(mContext.getPackageManager() - .queryIntentServicesAsUser(intent, matchFlags, userId)); + return new ParceledListSlice<>(mPackageManagerInt.queryIntentServices( + intent, matchFlags, uid, userId)); case ActivityManager.INTENT_SENDER_BROADCAST: - return new ParceledListSlice<>(mContext.getPackageManager() - .queryBroadcastReceiversAsUser(intent, matchFlags, userId)); + return new ParceledListSlice<>(mPackageManagerInt.queryIntentReceivers( + intent, resolvedType, matchFlags, uid, userId, false)); default: // ActivityManager.INTENT_SENDER_ACTIVITY_RESULT throw new IllegalStateException("Unsupported intent sender type: " + res.key.type); } diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java index 262436d693ec..eb1fd3aa49be 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 @@ final class ProcessStateRecord { @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 d16fe1240d0c..d4ef638d0818 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 @@ public class AttentionManagerService extends SystemService { * * 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 @@ public class AttentionManagerService extends SystemService { @GuardedBy("mLock") private void cancelAndUnbindLocked() { synchronized (mLock) { - if (mCurrentAttentionCheck == null && mCurrentProximityUpdate == null) { - return; - } if (mCurrentAttentionCheck != null) { cancel(); } @@ -937,7 +937,7 @@ public class AttentionManagerService extends SystemService { } } - class TestableProximityUpdateCallbackInternal extends ProximityUpdateCallbackInternal { + class TestableProximityUpdateCallbackInternal implements ProximityUpdateCallbackInternal { private double mLastCallbackCode = PROXIMITY_UNKNOWN; @Override @@ -1069,6 +1069,7 @@ public class AttentionManagerService extends SystemService { 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 c00c29815891..0a081bfbee96 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 @@ public class AudioService extends IAudioService.Stub } 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 @@ public class AudioService extends IAudioService.Stub 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 @@ public class AudioService extends IAudioService.Stub + 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 8356134bc63b..5eaa9485628c 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 @@ public class SpatializerHelper { } 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 @@ public class SpatializerHelper { @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/location/contexthub/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java index 625f1936e28e..885789227a12 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java @@ -322,6 +322,17 @@ public class ContextHubClientBroker extends IContextHubClient.Stub } else { mPendingIntentRequest = new PendingIntentRequest(pendingIntent, nanoAppId); } + + if (packageName == null) { + String[] packages = mContext.getPackageManager().getPackagesForUid( + Binder.getCallingUid()); + if (packages != null && packages.length > 0) { + packageName = packages[0]; + } + Log.e(TAG, "createClient: Provided package name null. Using first package name " + + packageName); + } + mPackage = packageName; mAttributionTag = attributionTag; mTransactionManager = transactionManager; diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java index 5b2188ac078e..17638ccbe6cc 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java @@ -1024,6 +1024,9 @@ public class ContextHubService extends IContextHubService.Stub { } /* package */ void denyClientAuthState(int contextHubId, String packageName, long nanoAppId) { + Log.i(TAG, "Denying " + packageName + " access to " + Long.toHexString(nanoAppId) + + " on context hub # " + contextHubId); + mClientManager.forEachClientOfHub(contextHubId, client -> { if (client.getPackageName().equals(packageName)) { client.updateNanoAppAuthState( diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 057afe84c03d..2f34ccdb5c03 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -6685,6 +6685,20 @@ public class NotificationManagerService extends SystemService { } } + // 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); } @@ -7834,7 +7848,8 @@ public class NotificationManagerService extends SystemService { && (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 477b8da61e0f..729c521a4ce0 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.io.PrintWriter; 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 @@ public class PreferencesHelper implements RankingConfig { 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 @@ public class PreferencesHelper implements RankingConfig { 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 class PreferencesHelper implements RankingConfig { 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/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java index bdc571103ffd..5e0a18039152 100644 --- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java +++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java @@ -131,6 +131,17 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { } } + // For tests: just do the setting of various local variables without actually doing work + @VisibleForTesting + protected void initForTests(Context context, NotificationUsageStats usageStats, + LruCache peopleCache) { + mUserToContextMap = new ArrayMap<>(); + mBaseContext = context; + mUsageStats = usageStats; + mPeopleCache = peopleCache; + mEnabled = true; + } + public RankingReconsideration process(NotificationRecord record) { if (!mEnabled) { if (VERBOSE) Slog.i(TAG, "disabled"); @@ -179,7 +190,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { return NONE; } final PeopleRankingReconsideration prr = - validatePeople(context, key, extras, null, affinityOut); + validatePeople(context, key, extras, null, affinityOut, null); float affinity = affinityOut[0]; if (prr != null) { @@ -224,15 +235,21 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { return context; } - private RankingReconsideration validatePeople(Context context, + @VisibleForTesting + protected RankingReconsideration validatePeople(Context context, final NotificationRecord record) { final String key = record.getKey(); final Bundle extras = record.getNotification().extras; final float[] affinityOut = new float[1]; + ArraySet<String> phoneNumbersOut = new ArraySet<>(); final PeopleRankingReconsideration rr = - validatePeople(context, key, extras, record.getPeopleOverride(), affinityOut); + validatePeople(context, key, extras, record.getPeopleOverride(), affinityOut, + phoneNumbersOut); final float affinity = affinityOut[0]; record.setContactAffinity(affinity); + if (phoneNumbersOut.size() > 0) { + record.mergePhoneNumbers(phoneNumbersOut); + } if (rr == null) { mUsageStats.registerPeopleAffinity(record, affinity > NONE, affinity == STARRED_CONTACT, true /* cached */); @@ -243,7 +260,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { } private PeopleRankingReconsideration validatePeople(Context context, String key, Bundle extras, - List<String> peopleOverride, float[] affinityOut) { + List<String> peopleOverride, float[] affinityOut, ArraySet<String> phoneNumbersOut) { float affinity = NONE; if (extras == null) { return null; @@ -270,6 +287,15 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { } if (lookupResult != null) { affinity = Math.max(affinity, lookupResult.getAffinity()); + + // add all phone numbers associated with this lookup result, if they exist + // and if requested + if (phoneNumbersOut != null) { + ArraySet<String> phoneNumbers = lookupResult.getPhoneNumbers(); + if (phoneNumbers != null && phoneNumbers.size() > 0) { + phoneNumbersOut.addAll(phoneNumbers); + } + } } } if (++personIdx == MAX_PEOPLE) { @@ -289,7 +315,8 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { return new PeopleRankingReconsideration(context, key, pendingLookups); } - private String getCacheKey(int userId, String handle) { + @VisibleForTesting + protected static String getCacheKey(int userId, String handle) { return Integer.toString(userId) + ":" + handle; } @@ -485,7 +512,8 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { } } - private static class LookupResult { + @VisibleForTesting + protected static class LookupResult { private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000; // 1hr private final long mExpireMillis; @@ -574,7 +602,8 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { return mPhoneNumbers; } - private boolean isExpired() { + @VisibleForTesting + protected boolean isExpired() { return mExpireMillis < System.currentTimeMillis(); } diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java index eb635500580a..3d9e89aa1846 100644 --- a/services/core/java/com/android/server/pm/Computer.java +++ b/services/core/java/com/android/server/pm/Computer.java @@ -113,6 +113,8 @@ public interface Computer extends PackageDataSnapshot { @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits); @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, + long flags, int filterCallingUid, int userId); + @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, long flags, int userId); @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType, long flags, int userId, int callingUid, boolean includeInstantApps); diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 259ca655d2b9..4a640ce6274c 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -599,6 +599,15 @@ public class ComputerEngine implements Computer { resolveForStart, userId, intent); } + @NonNull + @Override + public final List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, + @PackageManager.ResolveInfoFlagsBits long flags, int filterCallingUid, int userId) { + return queryIntentActivitiesInternal( + intent, resolvedType, flags, 0 /*privateResolveFlags*/, filterCallingUid, + userId, false /*resolveForStart*/, true /*allowDynamicSplits*/); + } + public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) { return queryIntentActivitiesInternal( diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java index 652847ad1647..96f37424ea4a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java +++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java @@ -308,7 +308,8 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal { public final List<ResolveInfo> queryIntentActivities( Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int filterCallingUid, int userId) { - return snapshot().queryIntentActivitiesInternal(intent, resolvedType, flags, userId); + return snapshot().queryIntentActivitiesInternal(intent, resolvedType, flags, + filterCallingUid, userId); } @Override diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index d645bb211bc3..05cb42973a00 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3245,8 +3245,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onKeyguardOccludedChangedLw(boolean occluded) { - if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing() - && !WindowManagerService.sEnableShellTransitions) { + if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { mPendingKeyguardOccluded = occluded; mKeyguardOccludedChanged = true; } else { @@ -5107,18 +5106,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@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 e8a3dcd5635f..4f00992c713e 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 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * 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 685b744c8062..dad9584c6722 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 @@ public class Notifier { /** * 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 @@ public class Notifier { } 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 fec61ac8f2cf..9fe53fbfaf25 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 @@ public class PowerGroup { 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 @@ public class PowerGroup { 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 @@ public class PowerGroup { 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 @@ public class PowerGroup { 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 @@ public class PowerGroup { 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 dbf05f1cd7c7..bc93cb30e449 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 @@ public final class PowerManagerService extends SystemService return; } + Slog.i(TAG, "onFlip(): Face " + (isFaceDown ? "down." : "up.")); mIsFaceDown = isFaceDown; if (isFaceDown) { final long currentTime = mClock.uptimeMillis(); @@ -1888,12 +1889,13 @@ public final class PowerManagerService extends SystemService // 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 @@ public final class PowerManagerService extends SystemService @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 @@ public final class PowerManagerService extends SystemService 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 @@ public final class PowerManagerService extends SystemService } } 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 @@ public final class PowerManagerService extends SystemService @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 @@ public final class PowerManagerService extends SystemService @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 @@ public final class PowerManagerService extends SystemService } @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 @@ public final class PowerManagerService extends SystemService 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 @@ public final class PowerManagerService extends SystemService void onUserActivity() { synchronized (mLock) { mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP).setLastUserActivityTimeLocked( - mClock.uptimeMillis()); + mClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_OTHER); } } @@ -5590,7 +5599,8 @@ public final class PowerManagerService extends SystemService } @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 e7c4ba5b9efe..d2413f015003 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -70,6 +70,7 @@ import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_ 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; @@ -277,6 +278,8 @@ class ActivityMetricsLogger { 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. */ @@ -312,7 +315,7 @@ class ActivityMetricsLogger { @Nullable static TransitionInfo create(@NonNull ActivityRecord r, @NonNull LaunchingState launchingState, @Nullable ActivityOptions options, - boolean processRunning, boolean processSwitch, int processState, + boolean processRunning, boolean processSwitch, int processState, int processOomAdj, boolean newActivityCreated, int startResult) { if (startResult != START_SUCCESS && startResult != START_TASK_TO_FRONT) { return null; @@ -328,19 +331,20 @@ class ActivityMetricsLogger { transitionType = TYPE_TRANSITION_COLD_LAUNCH; } return new TransitionInfo(r, launchingState, options, transitionType, processRunning, - processSwitch, processState); + 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, int processState) { + 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 @@ -644,9 +648,15 @@ class ActivityMetricsLogger { // interesting. final boolean processSwitch = !processRunning || !processRecord.hasStartedActivity(launchedActivity); - final int processState = processRunning - ? processRecord.getCurrentProcState() - : PROCESS_STATE_NONEXISTENT; + 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) { @@ -654,6 +664,7 @@ class ActivityMetricsLogger { + " launchedActivity=" + launchedActivity + " processRunning=" + processRunning + " processSwitch=" + processSwitch + " processState=" + processState + + " processOomAdj=" + processOomAdj + " newActivityCreated=" + newActivityCreated + " info=" + info); } @@ -689,8 +700,8 @@ class ActivityMetricsLogger { } final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState, - options, processRunning, processSwitch, processState, newActivityCreated, - resultCode); + options, processRunning, processSwitch, processState, processOomAdj, + newActivityCreated, resultCode); if (newInfo == null) { abort(launchingState, "unrecognized launch"); return; @@ -1005,8 +1016,10 @@ class ActivityMetricsLogger { 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, processState)); + timestamp, uptime, transitionDelay, infoSnapshot, isHibernating, + processState, processOomAdj)); } mLoggerHandler.post(() -> logAppDisplayed(infoSnapshot)); if (info.mPendingFullyDrawn != null) { @@ -1019,7 +1032,7 @@ class ActivityMetricsLogger { // 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 processState) { + int processState, int processOomAdj) { final LogMaker builder = new LogMaker(APP_TRANSITION); builder.setPackageName(info.packageName); builder.setType(info.type); @@ -1086,7 +1099,8 @@ class ActivityMetricsLogger { isLoading, info.launchedActivityName.hashCode(), TimeUnit.NANOSECONDS.toMillis(transitionStartTimeNs), - processState); + 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 bd88c41b5268..635cf0e61685 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 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean mUseTransferredAnimation; + /** Whether we need to setup the animation to animate only within the letterbox. */ + private boolean mNeedsLetterboxedAnimation; + /** * @see #currentLaunchCanTurnScreenOn() */ @@ -1762,8 +1765,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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) { @@ -3247,7 +3254,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A rootTask.moveToFront(reason, task); // Report top activity change to tracking services and WM if (mRootWindowContainer.getTopResumedActivity() == this) { - mAtmService.setResumedActivityUncheckLocked(this, reason); + mAtmService.setLastResumedActivityUncheckLocked(this, reason); } return true; } @@ -5334,6 +5341,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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. * @@ -5877,7 +5896,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A try { mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, PauseActivityItem.obtain(finishing, false /* userLeaving */, - configChangeFlags, false /* dontReport */)); + configChangeFlags, false /* dontReport */, + false /* autoEnteringPip */)); } catch (Exception e) { Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e); } @@ -7261,6 +7281,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A .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 +7322,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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 +7349,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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 +7473,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mAnimationBoundsLayer = null; } + mNeedsAnimationBoundsLayer = false; + if (mNeedsLetterboxedAnimation) { + mNeedsLetterboxedAnimation = false; + updateLetterboxSurface(findMainWindow(), t); + } + if (mAnimatingActivityRegistry != null) { mAnimatingActivityRegistry.notifyFinished(this); } @@ -7445,7 +7491,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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 73237189da16..d4bbc86c4850 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** * 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mDemoteTopAppReasons &= ~DEMOTE_TOP_REASON_DURING_UNLOCKING; final WindowState notificationShade = mRootWindowContainer.getDefaultDisplay() .getDisplayPolicy().getNotificationShade(); - proc = notificationShade != null - ? mProcessMap.getProcess(notificationShade.mSession.mPid) : null; - } - if (proc == null) { - return; + proc = notificationShade != null ? notificationShade.getProcess() : null; } + 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(); @@ -3560,7 +3563,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // Continue the pausing process after entering pip. if (r.isState(PAUSING)) { r.getTask().schedulePauseActivity(r, false /* userLeaving */, - false /* pauseImmediately */, "auto-pip"); + false /* pauseImmediately */, true /* autoEnteringPip */, "auto-pip"); } } }; @@ -4621,7 +4624,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } /** Update AMS states when an activity is resumed. */ - void setResumedActivityUncheckLocked(ActivityRecord r, String reason) { + void setLastResumedActivityUncheckLocked(ActivityRecord r, String reason) { final Task task = r.getTask(); if (task.isActivityTypeStandard()) { if (mCurAppTimeTracker != r.appTimeTracker) { diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 208b001dfd0e..a870b8afe2f9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -2083,7 +2083,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { * activity releases the top state and reports back, message about acquiring top state will be * sent to the new top resumed activity. */ - void updateTopResumedActivityIfNeeded() { + void updateTopResumedActivityIfNeeded(String reason) { final ActivityRecord prevTopActivity = mTopResumedActivity; final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); if (topRootTask == null || topRootTask.getTopResumedActivity() == prevTopActivity) { @@ -2119,6 +2119,12 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { } mService.updateOomAdj(); } + // Update the last resumed activity and focused app when the top resumed activity changed + // because the new top resumed activity might be already resumed and thus won't have + // activity state change to update the records to AMS. + if (mTopResumedActivity != null) { + mService.setLastResumedActivityUncheckLocked(mTopResumedActivity, reason); + } scheduleTopResumedActivityStateIfNeeded(); mService.updateTopApp(mTopResumedActivity); diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index fb9d7e602210..5ac5f2e4bdaf 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 static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 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 @@ public class AppTransitionController { 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 04229063732f..b033dca465f4 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 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { @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 ecb9fe3a00cc..b6452543a988 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 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp 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 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp 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 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } 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 096ebe2fd080..1a34c93f2ad6 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 @@ public class DisplayPolicy { 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 class DisplayPolicy { } 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; } @@ -2746,6 +2746,19 @@ public class DisplayPolicy { 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 8dd58506ef0b..97609a7dd8ba 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 @@ public class DisplayRotation { 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 @@ public class DisplayRotation { 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 3e2d7c928936..506396a932fe 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 @@ class InsetsPolicy { 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 df3109ad33c7..27550d9e8186 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 @@ public class Letterbox { 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 @@ public class Letterbox { 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 @@ public class Letterbox { mDarkScrimAlphaSupplier = darkScrimAlphaSupplier; mDoubleTapCallbackX = doubleTapCallbackX; mDoubleTapCallbackY = doubleTapCallbackY; + mParentSurfaceSupplier = parentSurface; } /** @@ -121,7 +124,6 @@ public class Letterbox { mFullWindowSurface.layout(outer.left, outer.top, outer.right, outer.bottom, surfaceOrigin); } - /** * Gets the insets between the outer and inner rects. */ @@ -333,6 +335,7 @@ public class Letterbox { 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 @@ public class Letterbox { } 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 class Letterbox { 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 57c60f4ffc33..a469c6b39e7f 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 @@ final class LetterboxConfiguration { } /** - * 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 @@ final class LetterboxConfiguration { } /** - * 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 @@ final class LetterboxConfiguration { } /** - * 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 @@ final class LetterboxConfiguration { /** * 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 @@ final class LetterboxConfiguration { /** * 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 c8ed602b0f1d..317c93e63459 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 @@ final class LetterboxUiController { // 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 @@ final class LetterboxUiController { } } - boolean hasWallpaperBackgroudForLetterbox() { + boolean hasWallpaperBackgroundForLetterbox() { return mShowWallpaperForLetterboxBackground; } @@ -137,6 +137,11 @@ final class LetterboxUiController { 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 @@ final class LetterboxUiController { } 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 @@ final class LetterboxUiController { 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 @@ final class LetterboxUiController { } } + 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 @@ final class LetterboxUiController { } 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 @@ final class LetterboxUiController { private void updateRoundedCorners(WindowState mainWindow) { final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface(); if (windowSurface != null && windowSurface.isValid()) { - 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) { + final Transaction transaction = mActivityRecord.getSyncTransaction(); + + 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 @@ final class LetterboxUiController { 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 @@ final class LetterboxUiController { + 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 64749cf94ddf..a89894db4b4b 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 @@ public class PhysicalDisplaySwitchTransitionLauncher { 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/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index aab9d5bc8cf1..b79c6f44bad5 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -514,7 +514,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> void onChildPositionChanged(WindowContainer child) { mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, !mWmService.mPerDisplayFocusEnabled /* updateInputWindows */); - mTaskSupervisor.updateTopResumedActivityIfNeeded(); + mTaskSupervisor.updateTopResumedActivityIfNeeded("onChildPositionChanged"); } @Override diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java index c7f8a1e2068a..f3670e49f01e 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.Animator; 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 @@ class SurfaceAnimationRunner { 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,17 +458,21 @@ class SurfaceAnimationRunner { .setHidden(true) .setCallsite("DefaultTransitionHandler#startAnimation") .setOpaque(true) - .setBufferSize(edgeBounds.width(), edgeBounds.height()) + .setBufferSize(extensionRect.width(), extensionRect.height()) .build(); + 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 Surface surface = new Surface(edgeExtensionLayer); - surface.attachAndQueueBufferWithColorSpace(edgeBuffer.getHardwareBuffer(), - edgeBuffer.getColorSpace()); + Canvas c = surface.lockHardwareCanvas(); + c.drawRect(extensionRect, paint); + surface.unlockCanvasAndPost(c); surface.release(); - final float scaleX = getScaleXForExtensionSurface(edgeBounds, extensionRect); - final float scaleY = getScaleYForExtensionSurface(edgeBounds, extensionRect); - synchronized (mEdgeExtensionLock) { if (!mEdgeExtensions.containsKey(leash)) { // The animation leash has already been removed, so we don't want to attach the @@ -472,7 +481,6 @@ class SurfaceAnimationRunner { 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 @@ class SurfaceAnimationRunner { 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/Task.java b/services/core/java/com/android/server/wm/Task.java index 75552e079575..e1334dc0ab88 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -920,7 +920,7 @@ class Task extends TaskFragment { // If the original state is resumed, there is no state change to update focused app. // So here makes sure the activity focus is set if it is the top. if (r.isState(RESUMED) && r == mRootWindowContainer.getTopResumedActivity()) { - mAtmService.setResumedActivityUncheckLocked(r, reason); + mAtmService.setLastResumedActivityUncheckLocked(r, reason); } } if (!animate) { @@ -2439,11 +2439,7 @@ class Task extends TaskFragment { focusableTask.moveToFront(myReason); // Top display focused root task is changed, update top resumed activity if needed. if (rootTask.getTopResumedActivity() != null) { - mTaskSupervisor.updateTopResumedActivityIfNeeded(); - // Set focused app directly because if the next focused activity is already resumed - // (e.g. the next top activity is on a different display), there won't have activity - // state change to update it. - mAtmService.setResumedActivityUncheckLocked(rootTask.getTopResumedActivity(), reason); + mTaskSupervisor.updateTopResumedActivityIfNeeded(reason); } return rootTask; } diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 8220cae74dc8..0f46c4f166ae 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -323,6 +323,10 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { // Clear preferred top because the adding focusable task has a higher z-order. mPreferredTopFocusableRootTask = null; } + + // Update the top resumed activity because the preferred top focusable task may be changed. + mAtmService.mTaskSupervisor.updateTopResumedActivityIfNeeded("addChildTask"); + mAtmService.updateSleepIfNeededLocked(); onRootTaskOrderChanged(task); } @@ -416,12 +420,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { } // Update the top resumed activity because the preferred top focusable task may be changed. - mAtmService.mTaskSupervisor.updateTopResumedActivityIfNeeded(); - - final ActivityRecord r = child.getTopResumedActivity(); - if (r != null && r == mRootWindowContainer.getTopResumedActivity()) { - mAtmService.setResumedActivityUncheckLocked(r, "positionChildAt"); - } + mAtmService.mTaskSupervisor.updateTopResumedActivityIfNeeded("positionChildTaskAt"); if (mChildren.indexOf(child) != oldPosition) { onRootTaskOrderChanged(child); diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index f3f21103a7e8..679a231265d1 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -460,7 +460,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { final ActivityRecord prevR = mResumedActivity; mResumedActivity = r; - mTaskSupervisor.updateTopResumedActivityIfNeeded(); + mTaskSupervisor.updateTopResumedActivityIfNeeded(reason); if (r == null && prevR.mDisplayContent != null && prevR.mDisplayContent.getFocusedRootTask() == null) { // Only need to notify DWPC when no activity will resume. @@ -773,9 +773,6 @@ class TaskFragment extends WindowContainer<WindowContainer> { Slog.v(TAG, "set resumed activity to:" + record + " reason:" + reason); } setResumedActivity(record, reason + " - onActivityStateChanged"); - if (record == mRootWindowContainer.getTopResumedActivity()) { - mAtmService.setResumedActivityUncheckLocked(record, reason); - } mTaskSupervisor.mRecentTasks.add(record.getTask()); } } @@ -1621,7 +1618,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode " + "directly: %s, didAutoPip: %b", prev, didAutoPip); } else { - schedulePauseActivity(prev, userLeaving, pauseImmediately, reason); + schedulePauseActivity(prev, userLeaving, pauseImmediately, + false /* autoEnteringPip */, reason); } } else { mPausingActivity = null; @@ -1675,7 +1673,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { } void schedulePauseActivity(ActivityRecord prev, boolean userLeaving, - boolean pauseImmediately, String reason) { + boolean pauseImmediately, boolean autoEnteringPip, String reason) { ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev); try { EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev), @@ -1683,7 +1681,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), prev.token, PauseActivityItem.obtain(prev.finishing, userLeaving, - prev.configChangeFlags, pauseImmediately)); + prev.configChangeFlags, pauseImmediately, autoEnteringPip)); } catch (Exception e) { // Ignore exception, if process died other code will cleanup. Slog.w(TAG, "Exception thrown during pause", e); diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 88059e1a0d04..d615583f4d7f 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -49,7 +49,9 @@ import android.window.ITaskFragmentOrganizer; import android.window.ITaskFragmentOrganizerController; import android.window.TaskFragmentInfo; import android.window.TaskFragmentTransaction; +import android.window.WindowContainerTransaction; +import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.common.ProtoLog; import java.lang.annotation.Retention; @@ -68,6 +70,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr private final ActivityTaskManagerService mAtmService; private final WindowManagerGlobalLock mGlobalLock; + private final WindowOrganizerController mWindowOrganizerController; + /** * A Map which manages the relationship between * {@link ITaskFragmentOrganizer} and {@link TaskFragmentOrganizerState} @@ -82,9 +86,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr private final ArraySet<Task> mTmpTaskSet = new ArraySet<>(); - TaskFragmentOrganizerController(ActivityTaskManagerService atm) { - mAtmService = atm; + TaskFragmentOrganizerController(@NonNull ActivityTaskManagerService atm, + @NonNull WindowOrganizerController windowOrganizerController) { + mAtmService = requireNonNull(atm); mGlobalLock = atm.mGlobalLock; + mWindowOrganizerController = requireNonNull(windowOrganizerController); } /** @@ -131,6 +137,14 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr private final SparseArray<RemoteAnimationDefinition> mRemoteAnimationDefinitions = new SparseArray<>(); + /** + * List of {@link TaskFragmentTransaction#getTransactionToken()} that have been sent to the + * organizer. If the transaction is sent during a transition, the + * {@link TransitionController} will wait until the transaction is finished. + * @see #onTransactionFinished(IBinder) + */ + private final List<IBinder> mRunningTransactions = new ArrayList<>(); + TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer, int pid, int uid) { mOrganizer = organizer; mOrganizerPid = pid; @@ -176,6 +190,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr taskFragment.removeImmediately(); mOrganizedTaskFragments.remove(taskFragment); } + for (int i = mRunningTransactions.size() - 1; i >= 0; i--) { + // Cleanup any running transaction to unblock the current transition. + onTransactionFinished(mRunningTransactions.get(i)); + } mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/); } @@ -320,6 +338,40 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr .setActivityIntent(activity.intent) .setActivityToken(activityToken); } + + void dispatchTransaction(@NonNull TaskFragmentTransaction transaction) { + if (transaction.isEmpty()) { + return; + } + try { + mOrganizer.onTransactionReady(transaction); + } catch (RemoteException e) { + Slog.d(TAG, "Exception sending TaskFragmentTransaction", e); + return; + } + onTransactionStarted(transaction.getTransactionToken()); + } + + /** Called when the transaction is sent to the organizer. */ + void onTransactionStarted(@NonNull IBinder transactionToken) { + if (!mWindowOrganizerController.getTransitionController().isCollecting()) { + return; + } + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, + "Defer transition ready for TaskFragmentTransaction=%s", transactionToken); + mRunningTransactions.add(transactionToken); + mWindowOrganizerController.getTransitionController().deferTransitionReady(); + } + + /** Called when the transaction is finished. */ + void onTransactionFinished(@NonNull IBinder transactionToken) { + if (!mRunningTransactions.remove(transactionToken)) { + return; + } + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, + "Continue transition ready for TaskFragmentTransaction=%s", transactionToken); + mWindowOrganizerController.getTransitionController().continueTransitionReady(); + } } @Nullable @@ -336,7 +388,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } @Override - public void registerOrganizer(ITaskFragmentOrganizer organizer) { + public void registerOrganizer(@NonNull ITaskFragmentOrganizer organizer) { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); synchronized (mGlobalLock) { @@ -354,7 +406,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } @Override - public void unregisterOrganizer(ITaskFragmentOrganizer organizer) { + public void unregisterOrganizer(@NonNull ITaskFragmentOrganizer organizer) { validateAndGetState(organizer); final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); @@ -372,8 +424,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } @Override - public void registerRemoteAnimations(ITaskFragmentOrganizer organizer, int taskId, - RemoteAnimationDefinition definition) { + public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId, + @NonNull RemoteAnimationDefinition definition) { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); synchronized (mGlobalLock) { @@ -398,7 +450,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } @Override - public void unregisterRemoteAnimations(ITaskFragmentOrganizer organizer, int taskId) { + public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId) { final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); synchronized (mGlobalLock) { @@ -416,6 +468,17 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } + @Override + public void onTransactionHandled(@NonNull ITaskFragmentOrganizer organizer, + @NonNull IBinder transactionToken, @NonNull WindowContainerTransaction wct) { + synchronized (mGlobalLock) { + // Keep the calling identity to avoid unsecure change. + mWindowOrganizerController.applyTransaction(wct); + final TaskFragmentOrganizerState state = validateAndGetState(organizer); + state.onTransactionFinished(transactionToken); + } + } + /** * Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. Returns * {@code null} if it doesn't, or if the organizer has activity(ies) embedded in untrusted mode. @@ -775,13 +838,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } final int organizerNum = mPendingTaskFragmentEvents.size(); for (int i = 0; i < organizerNum; i++) { - final ITaskFragmentOrganizer organizer = mTaskFragmentOrganizerState.get( - mPendingTaskFragmentEvents.keyAt(i)).mOrganizer; - dispatchPendingEvents(organizer, mPendingTaskFragmentEvents.valueAt(i)); + final TaskFragmentOrganizerState state = + mTaskFragmentOrganizerState.get(mPendingTaskFragmentEvents.keyAt(i)); + dispatchPendingEvents(state, mPendingTaskFragmentEvents.valueAt(i)); } } - void dispatchPendingEvents(@NonNull ITaskFragmentOrganizer organizer, + void dispatchPendingEvents(@NonNull TaskFragmentOrganizerState state, @NonNull List<PendingTaskFragmentEvent> pendingEvents) { if (pendingEvents.isEmpty()) { return; @@ -817,7 +880,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr if (mTmpTaskSet.add(task)) { // Make sure the organizer know about the Task config. transaction.addChange(prepareChange(new PendingTaskFragmentEvent.Builder( - PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED, organizer) + PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED, state.mOrganizer) .setTask(task) .build())); } @@ -825,7 +888,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr transaction.addChange(prepareChange(event)); } mTmpTaskSet.clear(); - dispatchTransactionInfo(organizer, transaction); + state.dispatchTransaction(transaction); pendingEvents.removeAll(candidateEvents); } @@ -855,6 +918,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } final ITaskFragmentOrganizer organizer = taskFragment.getTaskFragmentOrganizer(); + final TaskFragmentOrganizerState state = validateAndGetState(organizer); final TaskFragmentTransaction transaction = new TaskFragmentTransaction(); // Make sure the organizer know about the Task config. transaction.addChange(prepareChange(new PendingTaskFragmentEvent.Builder( @@ -862,22 +926,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr .setTask(taskFragment.getTask()) .build())); transaction.addChange(prepareChange(event)); - dispatchTransactionInfo(event.mTaskFragmentOrg, transaction); + state.dispatchTransaction(transaction); mPendingTaskFragmentEvents.get(organizer.asBinder()).remove(event); } - private void dispatchTransactionInfo(@NonNull ITaskFragmentOrganizer organizer, - @NonNull TaskFragmentTransaction transaction) { - if (transaction.isEmpty()) { - return; - } - try { - organizer.onTransactionReady(transaction); - } catch (RemoteException e) { - Slog.d(TAG, "Exception sending TaskFragmentTransaction", e); - } - } - @Nullable private TaskFragmentTransaction.Change prepareChange( @NonNull PendingTaskFragmentEvent event) { diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index fa2ab31904a3..2d3e437bed60 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1641,6 +1641,19 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe 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; } @@ -1802,6 +1815,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe /** This undoes one call to {@link #deferTransitionReady}. */ void continueTransitionReady() { --mReadyTracker.mDeferReadyDepth; + // Apply ready in case it is waiting for the previous defer call. + applyReady(); } /** diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 4f324f22aa5e..846aa3e3739a 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 @@ class TransitionController { } /** - * 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 25193d0b5ba3..797904890f74 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 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< 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 6415918e2ecc..dce0fbe42f3c 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.LayoutParams.TYPE_WALLPAPER; 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 @@ public class WindowManagerService extends IWindowManager.Stub }, 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)); - - setAnimatorDurationScale(Settings.Global.getFloat(resolver, - Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting)); + mWindowAnimationScaleSetting = getWindowAnimationScaleSetting(); + mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting(); + + setAnimatorDurationScale(getAnimatorDurationScaleSetting()); mForceDesktopModeOnExternalDisplays = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0; @@ -1405,6 +1401,22 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub } } - 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 3b9cd368a93b..68b1d354272d 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -147,7 +147,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub mGlobalLock = atm.mGlobalLock; mTaskOrganizerController = new TaskOrganizerController(mService); mDisplayAreaOrganizerController = new DisplayAreaOrganizerController(mService); - mTaskFragmentOrganizerController = new TaskFragmentOrganizerController(atm); + mTaskFragmentOrganizerController = new TaskFragmentOrganizerController(atm, this); } void setWindowManager(WindowManagerService wms) { @@ -397,17 +397,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub 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 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub 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 87b0c8b77904..202fe558f938 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 android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio 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 41bcbf6736dc..2432afbc03ef 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return wpc != null && wpc.registeredForDisplayAreaConfigChanges(); } + WindowProcessController getProcess() { + return mWpcForDisplayAreaConfigChanges; + } + /** * Fills the given window frames and merged configuration for the client. * @@ -6049,7 +6053,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } boolean hasWallpaperForLetterboxBackground() { - return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox(); + return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroundForLetterbox(); } /** 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 e2c3a94fc187..4c939f077940 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 @@ public class VirtualAudioControllerTest { 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 911fb6a87e96..08c2c6e6f26e 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 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { } @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 8171540c3acc..d78ca1bd7b67 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -4239,6 +4239,59 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @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; 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 598a22bbde39..d62ac99e530b 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.net.Uri; 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 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @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/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java index c12f0a965146..d72cfc70fc02 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java @@ -17,7 +17,9 @@ package com.android.server.notification; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.eq; @@ -30,6 +32,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; +import android.app.NotificationChannel; import android.app.Person; import android.content.ContentProvider; import android.content.ContentResolver; @@ -39,8 +42,11 @@ import android.net.Uri; import android.os.Bundle; import android.os.UserManager; import android.provider.ContactsContract; +import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; import android.text.SpannableString; +import android.util.ArraySet; +import android.util.LruCache; import androidx.test.runner.AndroidJUnit4; @@ -323,6 +329,69 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { isNull()); // sort order } + @Test + public void testValidatePeople_needsLookupWhenNoCache() { + final Context mockContext = mock(Context.class); + final ContentResolver mockContentResolver = mock(ContentResolver.class); + when(mockContext.getContentResolver()).thenReturn(mockContentResolver); + final NotificationUsageStats mockNotificationUsageStats = + mock(NotificationUsageStats.class); + + // Create validator with empty cache + ValidateNotificationPeople vnp = new ValidateNotificationPeople(); + LruCache cache = new LruCache<String, ValidateNotificationPeople.LookupResult>(5); + vnp.initForTests(mockContext, mockNotificationUsageStats, cache); + + NotificationRecord record = getNotificationRecord(); + String[] callNumber = new String[]{"tel:12345678910"}; + setNotificationPeople(record, callNumber); + + // Returned ranking reconsideration not null indicates that there is a lookup to be done + RankingReconsideration rr = vnp.validatePeople(mockContext, record); + assertNotNull(rr); + } + + @Test + public void testValidatePeople_noLookupWhenCached_andPopulatesContactInfo() { + final Context mockContext = mock(Context.class); + final ContentResolver mockContentResolver = mock(ContentResolver.class); + when(mockContext.getContentResolver()).thenReturn(mockContentResolver); + when(mockContext.getUserId()).thenReturn(1); + final NotificationUsageStats mockNotificationUsageStats = + mock(NotificationUsageStats.class); + + // Information to be passed in & returned from the lookup result + String lookup = "lookup:contactinfohere"; + String lookupTel = "16175551234"; + float affinity = 0.7f; + + // Create a fake LookupResult for the data we'll pass in + LruCache cache = new LruCache<String, ValidateNotificationPeople.LookupResult>(5); + ValidateNotificationPeople.LookupResult lr = + mock(ValidateNotificationPeople.LookupResult.class); + when(lr.getAffinity()).thenReturn(affinity); + when(lr.getPhoneNumbers()).thenReturn(new ArraySet<>(new String[]{lookupTel})); + when(lr.isExpired()).thenReturn(false); + cache.put(ValidateNotificationPeople.getCacheKey(1, lookup), lr); + + // Create validator with the established cache + ValidateNotificationPeople vnp = new ValidateNotificationPeople(); + vnp.initForTests(mockContext, mockNotificationUsageStats, cache); + + NotificationRecord record = getNotificationRecord(); + String[] peopleInfo = new String[]{lookup}; + setNotificationPeople(record, peopleInfo); + + // Returned ranking reconsideration null indicates that there is no pending work to be done + RankingReconsideration rr = vnp.validatePeople(mockContext, record); + assertNull(rr); + + // Confirm that the affinity & phone number made it into our record + assertEquals(affinity, record.getContactAffinity(), 1e-8); + assertNotNull(record.getPhoneNumbers()); + assertTrue(record.getPhoneNumbers().contains(lookupTel)); + } + // Creates a cursor that points to one item of Contacts data with the specified // columns. private Cursor makeMockCursor(int id, String lookupKey, int starred, int hasPhone) { @@ -365,4 +434,17 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { String resultString = Arrays.toString(result); assertEquals(message + ": arrays differ", expectedString, resultString); } + + private NotificationRecord getNotificationRecord() { + StatusBarNotification sbn = mock(StatusBarNotification.class); + Notification notification = mock(Notification.class); + when(sbn.getNotification()).thenReturn(notification); + return new NotificationRecord(mContext, sbn, mock(NotificationChannel.class)); + } + + private void setNotificationPeople(NotificationRecord r, String[] people) { + Bundle extras = new Bundle(); + extras.putObject(Notification.EXTRA_PEOPLE_LIST, people); + r.getSbn().getNotification().extras = extras; + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java index 75ecfd870eb2..d5e336b1cf2f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java @@ -228,7 +228,7 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase { mAtm.getTaskChangeNotificationController(); spyOn(taskChangeNotifier); - mAtm.setResumedActivityUncheckLocked(fullScreenActivityA, "resumeA"); + mAtm.setLastResumedActivityUncheckLocked(fullScreenActivityA, "resumeA"); verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskA.mTaskId) /* taskId */, eq(true) /* focused */); reset(taskChangeNotifier); @@ -237,7 +237,7 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase { .build(); final Task taskB = fullScreenActivityB.getTask(); - mAtm.setResumedActivityUncheckLocked(fullScreenActivityB, "resumeB"); + mAtm.setLastResumedActivityUncheckLocked(fullScreenActivityB, "resumeB"); verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskA.mTaskId) /* taskId */, eq(false) /* focused */); verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskB.mTaskId) /* taskId */, @@ -295,6 +295,7 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase { activity1.moveFocusableActivityToTop("test"); assertEquals(activity1.getUid(), pendingTopUid[0]); verify(mAtm).updateOomAdj(); + verify(mAtm).setLastResumedActivityUncheckLocked(any(), eq("test")); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 600881ea955c..be266c9f991e 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 @@ public class DisplayContentTests extends WindowTestsBase { 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 e502f2fbd173..d400a4c9daca 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 @@ public class LetterboxTest { 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 @@ public class LetterboxTest { 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 @@ public class LetterboxTest { } @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 8332cb4209ef..9274eb3f1490 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -25,6 +25,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; +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.TaskFragment.EMBEDDING_ALLOWED; @@ -46,7 +47,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -65,6 +65,7 @@ import android.window.TaskFragmentCreationParams; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOrganizer; import android.window.TaskFragmentOrganizerToken; +import android.window.TaskFragmentTransaction; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import android.window.WindowContainerTransactionCallback; @@ -90,6 +91,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { private TaskFragmentOrganizerController mController; private WindowOrganizerController mWindowOrganizerController; + private TransitionController mTransitionController; private TaskFragmentOrganizer mOrganizer; private TaskFragmentOrganizerToken mOrganizerToken; private ITaskFragmentOrganizer mIOrganizer; @@ -107,9 +109,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { private Task mTask; @Before - public void setup() { + public void setup() throws RemoteException { MockitoAnnotations.initMocks(this); mWindowOrganizerController = mAtm.mWindowOrganizerController; + mTransitionController = mWindowOrganizerController.mTransitionController; mController = mWindowOrganizerController.mTaskFragmentOrganizerController; mOrganizer = new TaskFragmentOrganizer(Runnable::run); mOrganizerToken = mOrganizer.getOrganizerToken(); @@ -128,11 +131,16 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { spyOn(mController); spyOn(mOrganizer); spyOn(mTaskFragment); + spyOn(mWindowOrganizerController); + spyOn(mTransitionController); doReturn(mIOrganizer).when(mTaskFragment).getTaskFragmentOrganizer(); doReturn(mTaskFragmentInfo).when(mTaskFragment).getTaskFragmentInfo(); doReturn(new SurfaceControl()).when(mTaskFragment).getSurfaceControl(); doReturn(mFragmentToken).when(mTaskFragment).getFragmentToken(); doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration(); + + // To prevent it from calling the real server. + doNothing().when(mOrganizer).onTransactionHandled(any(), any()); } @Test @@ -158,7 +166,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { 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 +174,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); - verify(mOrganizer).onTaskFragmentAppeared(any()); + verify(mOrganizer).onTaskFragmentAppeared(any(), any()); } @Test @@ -179,13 +187,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { 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 +203,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { 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 +212,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mTaskFragment); mController.dispatchPendingEvents(); - verify(mOrganizer).onTaskFragmentInfoChanged(eq(mTaskFragmentInfo)); + verify(mOrganizer).onTaskFragmentInfoChanged(any(), eq(mTaskFragmentInfo)); } @Test @@ -215,7 +223,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); - verify(mOrganizer).onTaskFragmentVanished(any()); + verify(mOrganizer).onTaskFragmentVanished(any(), any()); } @Test @@ -228,10 +236,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { 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(eq(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 +252,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { 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(eq(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 +268,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { 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 +277,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { 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 +285,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { 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 +294,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); - verify(mOrganizer).onTaskFragmentParentInfoChanged(eq(mTask.mTaskId), any()); + verify(mOrganizer).onTaskFragmentParentInfoChanged(any(), eq(mTask.mTaskId), any()); } @Test @@ -298,7 +306,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mErrorToken, null /* taskFragment */, -1 /* opType */, exception); mController.dispatchPendingEvents(); - verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), eq(null), eq(-1), + verify(mOrganizer).onTaskFragmentError(any(), eq(mErrorToken), eq(null), eq(-1), eq(exception)); } @@ -318,14 +326,14 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onActivityReparentedToTask(activity); mController.dispatchPendingEvents(); - verify(mOrganizer, never()).onActivityReparentedToTask(anyInt(), any(), any()); + verify(mOrganizer, never()).onActivityReparentedToTask(any(), anyInt(), any(), any()); // Notify organizer if it was embedded before entered Pip. activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer; mController.onActivityReparentedToTask(activity); mController.dispatchPendingEvents(); - verify(mOrganizer).onActivityReparentedToTask(eq(task.mTaskId), eq(activity.intent), + verify(mOrganizer).onActivityReparentedToTask(any(), eq(task.mTaskId), eq(activity.intent), eq(activity.token)); // Notify organizer if there is any embedded in the Task. @@ -341,7 +349,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.dispatchPendingEvents(); verify(mOrganizer, times(2)) - .onActivityReparentedToTask(eq(task.mTaskId), eq(activity.intent), + .onActivityReparentedToTask(any(), eq(task.mTaskId), eq(activity.intent), eq(activity.token)); } @@ -371,7 +379,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.dispatchPendingEvents(); // Allow organizer to reparent activity in other process using the temporary token. - verify(mOrganizer).onActivityReparentedToTask(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); @@ -801,7 +809,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.dispatchPendingEvents(); // Verifies that event was not sent - verify(mOrganizer, never()).onTaskFragmentInfoChanged(any()); + verify(mOrganizer, never()).onTaskFragmentInfoChanged(any(), any()); } @Test @@ -827,7 +835,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { 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()); @@ -835,7 +843,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // Verifies that event is sent. mController.dispatchPendingEvents(); - verify(mOrganizer).onTaskFragmentInfoChanged(any()); + verify(mOrganizer).onTaskFragmentInfoChanged(any(), any()); } /** @@ -866,10 +874,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { assertFalse(parentTask.shouldBeVisible(null)); // Verify the info changed callback still occurred despite the task being invisible - reset(mOrganizer); + clearInvocations(mOrganizer); mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment); mController.dispatchPendingEvents(); - verify(mOrganizer).onTaskFragmentInfoChanged(any()); + verify(mOrganizer).onTaskFragmentInfoChanged(any(), any()); } /** @@ -887,8 +895,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { .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 @@ -896,21 +904,21 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { 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); + clearInvocations(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()); } /** @@ -1020,7 +1028,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // 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)); } @@ -1059,7 +1067,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // 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)); } @@ -1092,6 +1100,40 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { .that(mTaskFragment.getBounds()).isEqualTo(task.getBounds()); } + @Test + public void testOnTransactionReady_invokeOnTransactionHandled() { + mController.registerOrganizer(mIOrganizer); + final TaskFragmentTransaction transaction = new TaskFragmentTransaction(); + mOrganizer.onTransactionReady(transaction); + + // Organizer should always trigger #onTransactionHandled when receives #onTransactionReady + verify(mOrganizer).onTransactionHandled(eq(transaction.getTransactionToken()), any()); + verify(mOrganizer, never()).applyTransaction(any()); + } + + @Test + public void testDispatchTransaction_deferTransitionReady() { + mController.registerOrganizer(mIOrganizer); + setupMockParent(mTaskFragment, mTask); + final ArgumentCaptor<IBinder> tokenCaptor = ArgumentCaptor.forClass(IBinder.class); + final ArgumentCaptor<WindowContainerTransaction> wctCaptor = + ArgumentCaptor.forClass(WindowContainerTransaction.class); + doReturn(true).when(mTransitionController).isCollecting(); + + mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); + mController.dispatchPendingEvents(); + + // Defer transition when send TaskFragment transaction during transition collection. + verify(mTransitionController).deferTransitionReady(); + verify(mOrganizer).onTransactionHandled(tokenCaptor.capture(), wctCaptor.capture()); + + mController.onTransactionHandled(mIOrganizer, tokenCaptor.getValue(), wctCaptor.getValue()); + + // Apply the organizer change and continue transition. + verify(mWindowOrganizerController).applyTransaction(wctCaptor.getValue()); + verify(mTransitionController).continueTransitionReady(); + } + /** * Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls * {@link WindowOrganizerController#applyTransaction} to apply the transaction, 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 851be9d77348..d2cb7ba5d311 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 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public void userActivity() { + public void userActivity(int displayGroupId, int event) { } @Override diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index 25db81fa2667..bde9c3dfd641 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 @@ package com.android.server.voiceinteraction; 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 static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPH 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 class HotwordDetectionConnection { 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 @@ final class HotwordDetectionConnection { 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 @@ final class HotwordDetectionConnection { 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 @@ final class HotwordDetectionConnection { if (mAudioFlinger != null) { mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0); } + if (mAttentionManagerInternal != null) { + mAttentionManagerInternal.onStopProximityUpdates(mProximityCallbackInternal); + } } void updateStateLocked(PersistableBundle options, SharedMemory sharedMemory) { @@ -460,6 +478,7 @@ final class HotwordDetectionConnection { mSoftwareCallback.onError(); return; } + saveProximityMetersToBundle(result); mSoftwareCallback.onDetected(result, null, null); if (result != null) { Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result) @@ -564,6 +583,7 @@ final class HotwordDetectionConnection { 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 @@ final class HotwordDetectionConnection { 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 @@ final class HotwordDetectionConnection { }); } + 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); |