diff options
503 files changed, 7936 insertions, 3024 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java index 7393bcde13b6..21ed1eb6bef8 100644 --- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java +++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java @@ -37,7 +37,9 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.Parcel; import android.os.Parcelable; +import android.os.Process; import android.os.RemoteException; +import android.os.UserHandle; import android.os.WorkSource; import android.text.TextUtils; import android.util.Log; @@ -91,6 +93,14 @@ import java.util.concurrent.Executor; public class AlarmManager { private static final String TAG = "AlarmManager"; + /** + * Prefix used by {{@link #makeTag(long, WorkSource)}} to make a tag on behalf of the caller + * when the {@link #set(int, long, long, long, OnAlarmListener, Handler, WorkSource)} API is + * used. This prefix is a unique sequence of characters to differentiate with other tags that + * apps may provide to other APIs that accept a listener callback. + */ + private static final String GENERATED_TAG_PREFIX = "$android.alarm.generated"; + /** @hide */ @IntDef(prefix = { "RTC", "ELAPSED" }, value = { RTC_WAKEUP, @@ -861,6 +871,24 @@ public class AlarmManager { } /** + * This is only used to make an identifying tag for the deprecated + * {@link #set(int, long, long, long, OnAlarmListener, Handler, WorkSource)} API which doesn't + * accept a tag. For all other APIs, the tag provided by the app is used, even if it is + * {@code null}. + */ + private static String makeTag(long triggerMillis, WorkSource ws) { + final StringBuilder tagBuilder = new StringBuilder(GENERATED_TAG_PREFIX); + + tagBuilder.append(":"); + final int attributionUid = + (ws == null || ws.isEmpty()) ? Process.myUid() : ws.getAttributionUid(); + tagBuilder.append(UserHandle.formatUid(attributionUid)); + tagBuilder.append(":"); + tagBuilder.append(triggerMillis); + return tagBuilder.toString(); + } + + /** * Direct callback version of {@link #set(int, long, long, long, PendingIntent, WorkSource)}. * Note that repeating alarms must use the PendingIntent variant, not an OnAlarmListener. * <p> @@ -875,8 +903,8 @@ public class AlarmManager { public void set(@AlarmType int type, long triggerAtMillis, long windowMillis, long intervalMillis, OnAlarmListener listener, Handler targetHandler, WorkSource workSource) { - setImpl(type, triggerAtMillis, windowMillis, intervalMillis, 0, null, listener, null, - targetHandler, workSource, null); + setImpl(type, triggerAtMillis, windowMillis, intervalMillis, 0, null, listener, + makeTag(triggerAtMillis, workSource), targetHandler, workSource, null); } /** diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 8c00c6a4bfd8..c0e89d2c4a05 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3452,7 +3452,7 @@ package android.window { public class WindowOrganizer { ctor public WindowOrganizer(); - method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public void applyTransaction(@NonNull android.window.WindowContainerTransaction); } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 3d5c34c38431..76475f2142c0 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -649,8 +649,11 @@ public abstract class BatteryStats implements Parcelable { return Uid.PROCESS_STATE_NONEXISTENT; } else if (procState == ActivityManager.PROCESS_STATE_TOP) { return Uid.PROCESS_STATE_TOP; - } else if (ActivityManager.isForegroundService(procState)) { - // State when app has put itself in the foreground. + } else if (procState == ActivityManager.PROCESS_STATE_BOUND_TOP) { + return Uid.PROCESS_STATE_BACKGROUND; + } else if (procState == ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) { + return Uid.PROCESS_STATE_FOREGROUND_SERVICE; + } else if (procState == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { return Uid.PROCESS_STATE_FOREGROUND_SERVICE; } else if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { // Persistent and other foreground states go here. diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java index 91d231eb1c39..787b609ab2c1 100644 --- a/core/java/android/os/UidBatteryConsumer.java +++ b/core/java/android/os/UidBatteryConsumer.java @@ -51,8 +51,7 @@ public final class UidBatteryConsumer extends BatteryConsumer { } /** - * The state of an application when it is either running a foreground (top) activity - * or a foreground service. + * The state of an application when it is either running a foreground (top) activity. */ public static final int STATE_FOREGROUND = 0; @@ -64,7 +63,8 @@ public final class UidBatteryConsumer extends BatteryConsumer { * {@link android.app.ActivityManager#PROCESS_STATE_TRANSIENT_BACKGROUND}, * {@link android.app.ActivityManager#PROCESS_STATE_BACKUP}, * {@link android.app.ActivityManager#PROCESS_STATE_SERVICE}, - * {@link android.app.ActivityManager#PROCESS_STATE_RECEIVER}. + * {@link android.app.ActivityManager#PROCESS_STATE_RECEIVER}, + * {@link android.app.ActivityManager#PROCESS_STATE_FOREGROUND_SERVICE}. */ public static final int STATE_BACKGROUND = 1; diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 6a4710f9475a..d79ea8929047 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -234,6 +234,7 @@ public class DreamService extends Service implements Window.Callback { private boolean mCanDoze; private boolean mDozing; private boolean mWindowless; + private boolean mOverlayFinishing; private int mDozeScreenState = Display.STATE_UNKNOWN; private int mDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT; @@ -1051,6 +1052,7 @@ public class DreamService extends Service implements Window.Callback { // We must unbind from any overlay connection if we are unbound before finishing. if (mOverlayConnection != null) { mOverlayConnection.unbind(); + mOverlayConnection = null; } return super.onUnbind(intent); @@ -1067,7 +1069,9 @@ public class DreamService extends Service implements Window.Callback { // If there is an active overlay connection, signal that the dream is ending before // continuing. Note that the overlay cannot rely on the unbound state, since another dream // might have bound to it in the meantime. - if (mOverlayConnection != null) { + if (mOverlayConnection != null && !mOverlayFinishing) { + // Set mOverlayFinish to true to only allow this consumer to be added once. + mOverlayFinishing = true; mOverlayConnection.addConsumer(overlay -> { try { overlay.endDream(); @@ -1300,9 +1304,10 @@ public class DreamService extends Service implements Window.Callback { * Must run on mHandler. * * @param dreamToken Token for this dream service. - * @param started A callback that will be invoked once onDreamingStarted has completed. + * @param started A callback that will be invoked once onDreamingStarted has completed. */ - private void attach(IBinder dreamToken, boolean canDoze, IRemoteCallback started) { + private void attach(IBinder dreamToken, boolean canDoze, boolean isPreviewMode, + IRemoteCallback started) { if (mDreamToken != null) { Slog.e(mTag, "attach() called when dream with token=" + mDreamToken + " already attached"); @@ -1350,7 +1355,8 @@ public class DreamService extends Service implements Window.Callback { i.putExtra(DreamActivity.EXTRA_CALLBACK, new DreamActivityCallbacks(mDreamToken)); final ServiceInfo serviceInfo = fetchServiceInfo(this, new ComponentName(this, getClass())); - i.putExtra(DreamActivity.EXTRA_DREAM_TITLE, fetchDreamLabel(this, serviceInfo)); + i.putExtra(DreamActivity.EXTRA_DREAM_TITLE, + fetchDreamLabel(this, serviceInfo, isPreviewMode)); try { if (!ActivityTaskManager.getService().startDreamActivity(i)) { @@ -1466,10 +1472,18 @@ public class DreamService extends Service implements Window.Callback { @Nullable private static CharSequence fetchDreamLabel(Context context, - @Nullable ServiceInfo serviceInfo) { - if (serviceInfo == null) return null; + @Nullable ServiceInfo serviceInfo, + boolean isPreviewMode) { + if (serviceInfo == null) { + return null; + } final PackageManager pm = context.getPackageManager(); - return serviceInfo.loadLabel(pm); + final CharSequence dreamLabel = serviceInfo.loadLabel(pm); + if (!isPreviewMode || dreamLabel == null) { + return dreamLabel; + } + // When in preview mode, return a special label indicating the dream is in preview. + return context.getResources().getString(R.string.dream_preview_title, dreamLabel); } @Nullable @@ -1525,8 +1539,9 @@ public class DreamService extends Service implements Window.Callback { final class DreamServiceWrapper extends IDreamService.Stub { @Override public void attach(final IBinder dreamToken, final boolean canDoze, - IRemoteCallback started) { - mHandler.post(() -> DreamService.this.attach(dreamToken, canDoze, started)); + final boolean isPreviewMode, IRemoteCallback started) { + mHandler.post( + () -> DreamService.this.attach(dreamToken, canDoze, isPreviewMode, started)); } @Override diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl index ce0435498917..8b5d8754647c 100644 --- a/core/java/android/service/dreams/IDreamService.aidl +++ b/core/java/android/service/dreams/IDreamService.aidl @@ -22,7 +22,7 @@ import android.os.IRemoteCallback; * @hide */ oneway interface IDreamService { - void attach(IBinder windowToken, boolean canDoze, IRemoteCallback started); + void attach(IBinder windowToken, boolean canDoze, boolean isPreviewMode, IRemoteCallback started); void detach(); void wakeUp(); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index b231934ee592..953f17a3a827 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1391,6 +1391,8 @@ public final class ViewRootImpl implements ViewParent, listener, listener.data, mHandler, true /*waitForPresentTime*/); mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver); } + // Update unbuffered request when set the root view. + mUnbufferedInputSource = mView.mUnbufferedInputSource; } view.assignParent(this); diff --git a/core/java/android/window/TaskFragmentAnimationParams.java b/core/java/android/window/TaskFragmentAnimationParams.java index 12ad91498626..c8f632707966 100644 --- a/core/java/android/window/TaskFragmentAnimationParams.java +++ b/core/java/android/window/TaskFragmentAnimationParams.java @@ -33,6 +33,13 @@ public final class TaskFragmentAnimationParams implements Parcelable { public static final TaskFragmentAnimationParams DEFAULT = new TaskFragmentAnimationParams.Builder().build(); + /** + * The default value for animation background color, which means to use the theme window + * background color. + */ + @ColorInt + public static final int DEFAULT_ANIMATION_BACKGROUND_COLOR = 0; + @ColorInt private final int mAnimationBackgroundColor; @@ -104,12 +111,13 @@ public final class TaskFragmentAnimationParams implements Parcelable { public static final class Builder { @ColorInt - private int mAnimationBackgroundColor = 0; + private int mAnimationBackgroundColor = DEFAULT_ANIMATION_BACKGROUND_COLOR; /** * Sets the {@link ColorInt} to use for the background during the animation with this * TaskFragment if the animation requires a background. The default value is - * {@code 0}, which is to use the theme window background. + * {@link #DEFAULT_ANIMATION_BACKGROUND_COLOR}, which is to use the theme window background + * color. * * @param color a packed color int, {@code AARRGGBB}, for the animation background color. * @return this {@link Builder}. diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java index 2a80d021abd6..740fbacbbfcc 100644 --- a/core/java/android/window/WindowOrganizer.java +++ b/core/java/android/window/WindowOrganizer.java @@ -61,9 +61,7 @@ public class WindowOrganizer { * Apply multiple WindowContainer operations at once. * * Note that using this API requires the caller to hold - * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, unless the caller is using - * {@link TaskFragmentOrganizer}, in which case it is allowed to change TaskFragment that is - * created by itself. + * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}. * * @param t The transaction to apply. * @param callback This transaction will use the synchronization scheme described in @@ -72,8 +70,7 @@ public class WindowOrganizer { * @return An ID for the sync operation which will later be passed to transactionReady callback. * This lets the caller differentiate overlapping sync operations. */ - @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS, - conditional = true) + @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public int applySyncTransaction(@NonNull WindowContainerTransaction t, @NonNull WindowContainerTransactionCallback callback) { try { diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java index 09e409bd934e..ac4976f2a46a 100644 --- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java +++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java @@ -298,18 +298,16 @@ public class BatteryUsageStatsProvider { BatteryStats.Uid.PROCESS_STATE_FOREGROUND, realtimeUs, BatteryStats.STATS_SINCE_CHARGED); - totalForegroundDurationUs += uid.getProcessStateTime( - BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE, realtimeUs, - BatteryStats.STATS_SINCE_CHARGED); - return totalForegroundDurationUs / 1000; } private long getProcessBackgroundTimeMs(BatteryStats.Uid uid, long realtimeUs) { - return uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND, realtimeUs, - BatteryStats.STATS_SINCE_CHARGED) / 1000; + return (uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND, + realtimeUs, BatteryStats.STATS_SINCE_CHARGED) + + uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE, + realtimeUs, BatteryStats.STATS_SINCE_CHARGED)) + / 1000; } - private BatteryUsageStats getAggregatedBatteryUsageStats(BatteryUsageStatsQuery query) { final boolean includePowerModels = (query.getFlags() & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0; diff --git a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java index 205c5fd735ea..d2b612a9e6f3 100644 --- a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java +++ b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java @@ -73,6 +73,23 @@ public class GestureNavigationSettingsObserver extends ContentObserver { mOnPropertiesChangedListener); } + public void registerForCurrentUser() { + ContentResolver r = mContext.getContentResolver(); + r.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT), + false, this); + r.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT), + false, this); + r.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), + false, this); + DeviceConfig.addOnPropertiesChangedListener( + DeviceConfig.NAMESPACE_SYSTEMUI, + runnable -> mMainHandler.post(runnable), + mOnPropertiesChangedListener); + } + public void unregister() { mContext.getContentResolver().unregisterContentObserver(this); DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index b1610d790222..8952f37b1469 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -428,7 +428,7 @@ static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj, jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return 0; } else if (err != NO_ERROR) { - jniThrowException(env, OutOfResourcesException, NULL); + jniThrowException(env, OutOfResourcesException, statusToString(err).c_str()); return 0; } diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index ca1d87fcd88d..4cf938470ea0 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -52,7 +52,7 @@ <string name="needPuk2" msgid="7032612093451537186">"Escriviu el PUK2 per desbloquejar la targeta SIM."</string> <string name="enablePin" msgid="2543771964137091212">"No és correcte; activa el bloqueig de RUIM/SIM."</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584"> - <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item> + <item quantity="many">Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents; si no l\'encertes, la SIM es bloquejarà.</item> <item quantity="other">Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents; si no l\'encertes, la SIM es bloquejarà.</item> <item quantity="one">Et queda <xliff:g id="NUMBER_0">%d</xliff:g> intent; si no l\'encertes, la SIM es bloquejarà.</item> </plurals> @@ -182,7 +182,7 @@ <string name="low_memory" product="watch" msgid="3479447988234030194">"L\'emmagatzematge del rellotge està ple. Suprimeix uns quants fitxers per alliberar espai."</string> <string name="low_memory" product="tv" msgid="6663680413790323318">"L\'espai d\'emmagatzematge del dispositiu Android TV és ple. Suprimeix alguns fitxers per alliberar espai."</string> <string name="low_memory" product="default" msgid="2539532364144025569">"L\'emmagatzematge del telèfon és ple. Suprimeix uns quants fitxers per alliberar espai."</string> - <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{L\'autoritat de certificació s\'ha instal·lat}many{Certificate authorities installed}other{Les autoritats de certificació s\'han instal·lat}}"</string> + <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{L\'autoritat de certificació s\'ha instal·lat}many{Les autoritats de certificació s\'han instal·lat}other{Les autoritats de certificació s\'han instal·lat}}"</string> <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Per un tercer desconegut"</string> <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Per l\'administrador del teu perfil de treball"</string> <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Per <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string> @@ -256,7 +256,7 @@ <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Utilitza aquesta opció en la majoria de circumstàncies. Et permet fer un seguiment del progrés de l\'informe, introduir més dades sobre el problema i fer captures de pantalla. És possible que ometi seccions poc utilitzades que requereixen molt de temps."</string> <string name="bugreport_option_full_title" msgid="7681035745950045690">"Informe complet"</string> <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilitza aquesta opció perquè la interferència en el sistema sigui mínima si el dispositiu no respon o va massa lent, o bé si necessites totes les seccions de l\'informe. No et permet introduir més dades ni fer més captures de pantalla."</string> - <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Es farà una captura de pantalla de l\'informe d\'errors d\'aquí a # segon.}many{Taking screenshot for bug report in # seconds.}other{Es farà una captura de pantalla de l\'informe d\'errors d\'aquí a # segons.}}"</string> + <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Es farà una captura de pantalla de l\'informe d\'errors d\'aquí a # segon.}many{Es farà una captura de pantalla de l\'informe d\'errors d\'aquí a # segons.}other{Es farà una captura de pantalla de l\'informe d\'errors d\'aquí a # segons.}}"</string> <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"S\'ha fet la captura de pantalla amb l\'informe d\'errors"</string> <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"No s\'ha pogut fer la captura de pantalla amb l\'informe d\'errors"</string> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode silenciós"</string> @@ -1090,7 +1090,7 @@ <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vol activar l\'exploració tàctil. Quan l\'exploració per tàctil està activada, pots escoltar o veure les descripcions del contingut seleccionat o utilitzar gestos per interaccionar amb el telèfon."</string> <string name="oneMonthDurationPast" msgid="4538030857114635777">"Fa 1 mes"</string> <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Fa més d\'1 mes"</string> - <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Darrer dia (#)}many{Last # days}other{# darrers dies}}"</string> + <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Darrer dia (#)}many{# darrers dies}other{# darrers dies}}"</string> <string name="last_month" msgid="1528906781083518683">"Darrer mes"</string> <string name="older" msgid="1645159827884647400">"Més antigues"</string> <string name="preposition_for_date" msgid="2780767868832729599">"el <xliff:g id="DATE">%s</xliff:g>"</string> @@ -1117,14 +1117,14 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> h"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> d"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> a"</string> - <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Fa # minut}many{# minutes ago}other{Fa # minuts}}"</string> - <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Fa # hora}many{# hours ago}other{Fa # hores}}"</string> - <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Fa # dia}many{# days ago}other{Fa # dies}}"</string> - <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Fa # any}many{# years ago}other{Fa # anys}}"</string> - <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minut}many{# minutes}other{# minuts}}"</string> - <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}many{# hours}other{# hores}}"</string> - <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}many{# days}other{# dies}}"</string> - <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# any}many{# years}other{# anys}}"</string> + <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Fa # minut}many{Fa # minuts}other{Fa # minuts}}"</string> + <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Fa # hora}many{Fa # hores}other{Fa # hores}}"</string> + <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Fa # dia}many{Fa # dies}other{Fa # dies}}"</string> + <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Fa # any}many{Fa # anys}other{Fa # anys}}"</string> + <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minut}many{# minuts}other{# minuts}}"</string> + <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}many{# hores}other{# hores}}"</string> + <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}many{# dies}other{# dies}}"</string> + <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# any}many{# anys}other{# anys}}"</string> <string name="VideoView_error_title" msgid="5750686717225068016">"Problema amb el vídeo"</string> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Aquest vídeo no és vàlid per a la reproducció en aquest dispositiu."</string> <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"No es pot reproduir aquest vídeo."</string> @@ -1511,7 +1511,7 @@ <string name="skip_button_label" msgid="3566599811326688389">"Omet"</string> <string name="no_matches" msgid="6472699895759164599">"No s\'ha trobat cap coincidència"</string> <string name="find_on_page" msgid="5400537367077438198">"Troba-ho a la pàgina"</string> - <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# coincidència}many{# of {total}}other{# de {total}}}"</string> + <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# coincidència}many{# de {total}}other{# de {total}}}"</string> <string name="action_mode_done" msgid="2536182504764803222">"Fet"</string> <string name="progress_erasing" msgid="6891435992721028004">"S\'està esborrant l\'emmagatzematge compartit…"</string> <string name="share" msgid="4157615043345227321">"Comparteix"</string> @@ -1866,14 +1866,14 @@ <string name="data_saver_description" msgid="4995164271550590517">"Per reduir l\'ús de dades, la funció Estalvi de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a les dades, però menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Vols activar l\'Estalvi de dades?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activa"</string> - <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durant 1 minut (fins a les {formattedTime})}many{For # minutes (until {formattedTime})}other{Durant # minuts (fins a les {formattedTime})}}"</string> - <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durant 1 min (fins a les {formattedTime})}many{For # min (until {formattedTime})}other{Durant # min (fins a les {formattedTime})}}"</string> - <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durant 1 hora (fins a les {formattedTime})}many{For # hours (until {formattedTime})}other{Durant # hores (fins a les {formattedTime})}}"</string> - <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durant 1 h (fins a les {formattedTime})}many{For # hr (until {formattedTime})}other{Durant # h (fins a les {formattedTime})}}"</string> - <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durant 1 minut}many{For # minutes}other{Durant # minuts}}"</string> - <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durant 1 min}many{For # min}other{Durant # min}}"</string> - <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durant 1 hora}many{For # hours}other{Durant # hores}}"</string> - <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durant 1 h}many{For # hr}other{Durant # h}}"</string> + <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durant 1 minut (fins a les {formattedTime})}many{Durant # minuts (fins a les {formattedTime})}other{Durant # minuts (fins a les {formattedTime})}}"</string> + <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durant 1 min (fins a les {formattedTime})}many{Durant # min (fins a les {formattedTime})}other{Durant # min (fins a les {formattedTime})}}"</string> + <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durant 1 hora (fins a les {formattedTime})}many{Durant # hores (fins a les {formattedTime})}other{Durant # hores (fins a les {formattedTime})}}"</string> + <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durant 1 h (fins a les {formattedTime})}many{Durant # h (fins a les {formattedTime})}other{Durant # h (fins a les {formattedTime})}}"</string> + <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durant 1 minut}many{Durant # minuts}other{Durant # minuts}}"</string> + <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durant 1 min}many{Durant # min}other{Durant # min}}"</string> + <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durant 1 hora}many{Durant # hores}other{Durant # hores}}"</string> + <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durant 1 h}many{Durant # h}other{Durant # h}}"</string> <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Finalitza: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string> <string name="zen_mode_until" msgid="2250286190237669079">"Fins a les <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string> <string name="zen_mode_alarm" msgid="7046911727540499275">"Fins a les <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (propera alarma)"</string> @@ -2004,7 +2004,7 @@ <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Desa per a emplenament automàtic"</string> <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"El contingut no es pot emplenar automàticament"</string> <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Cap suggeriment d\'emplenament automàtic"</string> - <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{1 suggeriment d\'emplenament automàtic}many{# autofill suggestions}other{# suggeriments d\'emplenament automàtic}}"</string> + <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{1 suggeriment d\'emplenament automàtic}many{# suggeriments d\'emplenament automàtic}other{# suggeriments d\'emplenament automàtic}}"</string> <string name="autofill_save_title" msgid="7719802414283739775">"Vols desar-ho a "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string> <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Vols desar <xliff:g id="TYPE">%1$s</xliff:g> a "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string> <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Vols desar <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> a "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string> @@ -2115,7 +2115,7 @@ <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentació <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"El Bluetooth es mantindrà activat durant el mode d\'avió"</string> <string name="car_loading_profile" msgid="8219978381196748070">"S\'està carregant"</string> - <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} i # fitxer}many{{file_name} + # files}other{{file_name} i # fitxers}}"</string> + <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} i # fitxer}many{{file_name} i # fitxers}other{{file_name} i # fitxers}}"</string> <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"No hi ha cap suggeriment de persones amb qui compartir"</string> <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Llista d\'aplicacions"</string> <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Aquesta aplicació no té permís de gravació, però pot capturar àudio a través d\'aquest dispositiu USB."</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 51688d30ac48..0e17b9ab4831 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -217,7 +217,7 @@ <string name="silent_mode" msgid="8796112363642579333">"Lydløs"</string> <string name="turn_on_radio" msgid="2961717788170634233">"Slå trådløs til"</string> <string name="turn_off_radio" msgid="7222573978109933360">"Slå trådløs fra"</string> - <string name="screen_lock" msgid="2072642720826409809">"Skærmlås"</string> + <string name="screen_lock" msgid="2072642720826409809">"Skærmlås"</string> <string name="power_off" msgid="4111692782492232778">"Sluk"</string> <string name="silent_mode_silent" msgid="5079789070221150912">"Ringeren er deaktiveret"</string> <string name="silent_mode_vibrate" msgid="8821830448369552678">"Ringervibrering"</string> @@ -241,7 +241,7 @@ <string name="global_actions" product="tablet" msgid="4412132498517933867">"Valgmuligheder for tabletcomputeren"</string> <string name="global_actions" product="tv" msgid="3871763739487450369">"Valgmuligheder for Android TV"</string> <string name="global_actions" product="default" msgid="6410072189971495460">"Indstillinger for telefon"</string> - <string name="global_action_lock" msgid="6949357274257655383">"Skærmlås"</string> + <string name="global_action_lock" msgid="6949357274257655383">"Skærmlås"</string> <string name="global_action_power_off" msgid="4404936470711393203">"Sluk"</string> <string name="global_action_power_options" msgid="1185286119330160073">"Afbryderknap"</string> <string name="global_action_restart" msgid="4678451019561687074">"Genstart"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 514f8efe0044..2f510555e883 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -52,7 +52,7 @@ <string name="needPuk2" msgid="7032612093451537186">"Escribir PUK2 para desbloquear la tarjeta SIM."</string> <string name="enablePin" msgid="2543771964137091212">"Error; habilita el bloqueo de SIM/RUIM."</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584"> - <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item> + <item quantity="many">Tienes <xliff:g id="NUMBER_1">%d</xliff:g> intentos más antes de que se bloquee la tarjeta SIM.</item> <item quantity="other">Tienes <xliff:g id="NUMBER_1">%d</xliff:g> intentos más antes de que se bloquee la tarjeta SIM.</item> <item quantity="one">Tienes <xliff:g id="NUMBER_0">%d</xliff:g> un intento más antes de que se bloquee la tarjeta SIM.</item> </plurals> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index f921c7bb5cb7..29e8abf44a6b 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -52,7 +52,7 @@ <string name="needPuk2" msgid="7032612093451537186">"Introduce el código PUK2 para desbloquear la tarjeta SIM."</string> <string name="enablePin" msgid="2543771964137091212">"Error, habilitar bloqueo de SIM/RUIM."</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584"> - <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item> + <item quantity="many">Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos para bloquear la tarjeta SIM.</item> <item quantity="other">Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos para bloquear la tarjeta SIM.</item> <item quantity="one">Te queda <xliff:g id="NUMBER_0">%d</xliff:g> intento para bloquear la tarjeta SIM.</item> </plurals> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 28d3e6afe483..fc7a86e21f20 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -427,9 +427,9 @@ <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Android TV gailuko deien erregistroa aldatzeko baimena ematen die aplikazioei, jasotako eta egindako deiei buruzko datuak barne. Baliteke asmo txarreko aplikazioek deien erregistroa ezabatzea edo aldatzea."</string> <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Telefonoaren deien erregistroa aldatzeko baimena ematen die aplikazioei, sarrerako eta irteerako deiei buruzko datuak barne. Asmo txarreko aplikazioek deien erregistroa ezabatzeko edo aldatzeko erabil dezakete."</string> <string name="permlab_bodySensors" msgid="662918578601619569">"Atzitu gorputz-sentsoreen datuak (esaterako, bihotz-maiztasuna) aplikazioa erabili bitartean"</string> - <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"Aplikazioak erabiltzen diren bitartean, gorputz-sentsoreen datuak (besteak beste, bihotz-maiztasuna, tenperatura eta odolean dagoen oxigenoaren ehunekoa) atzitzeko baimena ematen die aplikazio horiei."</string> + <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"Aplikazioak erabiltzen diren bitartean, gorputz-sentsoreen datuak (besteak beste, bihotz-maiztasuna, tenperatura eta odolean dagoen oxigenoaren ehunekoa) erabiltzeko baimena ematen die aplikazio horiei."</string> <string name="permlab_bodySensors_background" msgid="4912560779957760446">"Atzitu gorputz-sentsoreen datuak (adib., bihotz-maiztasunarenak) atzeko planoan"</string> - <string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"Aplikazioak atzeko planoan egon bitartean, gorputz-sentsoreen datuak (besteak beste, bihotz-maiztasuna, tenperatura eta odolean dagoen oxigenoaren ehunekoa) atzitzeko baimena ematen die aplikazio horiei."</string> + <string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"Aplikazioak atzeko planoan egon bitartean, gorputz-sentsoreen datuak (besteak beste, bihotz-maiztasuna, tenperatura eta odolean dagoen oxigenoaren ehunekoa) erabiltzeko baimena ematen die aplikazio horiei."</string> <string name="permlab_readCalendar" msgid="6408654259475396200">"irakurri egutegiko gertaerak eta xehetasunak"</string> <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Aplikazioak tabletan gordetako egutegiko gertaerak irakur ditzake eta egutegiko datuak parteka eta gorde ditzake."</string> <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Aplikazioak Android TV gailuan gordeta dituzun egutegiko gertaerak irakur ditzake, baita egutegiko datuak partekatu eta gorde ere."</string> @@ -439,7 +439,7 @@ <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"Android TV gailuan egutegiko gertaerak gehitzeko eta gehitutakoak kentzeko edo aldatzeko aukera dute aplikazioek. Gainera, egutegien jabeenak diruditen mezuak bidal ditzakete, edo gertaerak aldatu jabeei ezer esan gabe."</string> <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Telefonoko gertaerak gehitzeko, kentzeko edo aldatzeko aukera du aplikazioak. Gainera, egutegien jabeenak diruditen mezuak bidal ditzake, eta gertaerak alda ditzake jabeei beraiei jakinarazi gabe."</string> <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"atzitu kokapen-hornitzaileen komando gehigarriak"</string> - <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Kokapen-hornitzailearen agindu gehigarriak atzitzeko baimena ematen die aplikazioei. Horrela, agian aplikazioek GPSaren edo bestelako kokapenaren iturburuen funtzionamenduan eragina izan dezakete."</string> + <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Kokapen-hornitzailearen agindu gehigarriak erabiltzeko baimena ematen die aplikazioei. Horrela, agian aplikazioek GPSaren edo bestelako kokapenaren iturburuen funtzionamenduan eragina izan dezakete."</string> <string name="permlab_accessFineLocation" msgid="6426318438195622966">"lortu kokapen zehatza aurreko planoan bakarrik"</string> <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Abian denean, aplikazioak kokapen zehatza lor dezake kokapen-zerbitzuen bidez. Aplikazioak kokapena lortu ahal izateko, kokapen-zerbitzuek aktibatuta egon behar dute gailuan. Bateria-erabilera areagotzen du horrek."</string> <string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"atzitu gutxi gorabeherako kokapena aurreko planoan bakarrik"</string> @@ -460,21 +460,21 @@ <string name="permdesc_camera" msgid="5240801376168647151">"Aplikazioak abian den bitartean erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko."</string> <string name="permlab_backgroundCamera" msgid="7549917926079731681">"Argazkiak atera eta bideoak grabatu atzeko planoan."</string> <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Aplikazioak edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko."</string> - <string name="permlab_systemCamera" msgid="3642917457796210580">"eman sistemako kamerak atzitzeko baimena aplikazio edo zerbitzu bati argazkiak ateratzeko eta bideoak grabatzeko"</string> + <string name="permlab_systemCamera" msgid="3642917457796210580">"eman sistemako kamerak erabiltzeko baimena aplikazio edo zerbitzu bati argazkiak ateratzeko eta bideoak grabatzeko"</string> <string name="permdesc_systemCamera" msgid="5938360914419175986">"Pribilegioa duen edo sistemakoa den aplikazio honek edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko. Halaber, android.permission.CAMERA baimena izan behar du aplikazioak."</string> <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"eman jakinarazpenak jasotzeko baimena aplikazioari edo zerbitzuari kamerak ireki edo ixten direnean."</string> <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Kamera ireki edo itxi dela (eta zer aplikaziorekin) dioten jakinarazpenak jaso ditzake aplikazio honek."</string> <string name="permlab_vibrate" msgid="8596800035791962017">"kontrolatu dardara"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"Bibragailua kontrolatzeko baimena ematen die aplikazioei."</string> - <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Dardara-egoera atzitzeko baimena ematen die aplikazioei."</string> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Dardara-egoera erabiltzeko baimena ematen die aplikazioei."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"deitu zuzenean telefono-zenbakietara"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"Telefono-zenbakietara zuk esku hartu gabe deitzeko baimena ematen die aplikazioei. Horrela, ustekabeko gastuak edo deiak eragin daitezke. Asmo txarreko aplikazioek erabil dezakete zuk berretsi gabeko deiak eginda gastuak eragiteko."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"atzitu IMS dei-zerbitzua"</string> <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Zuk ezer egin beharrik gabe deiak egiteko IMS zerbitzua erabiltzeko baimena ematen die aplikazioei."</string> <string name="permlab_readPhoneState" msgid="8138526903259297969">"irakurri telefonoaren egoera eta identitatea"</string> - <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Gailuaren telefono-eginbideak atzitzeko baimena ematen die aplikazioei. Baimen horrek aplikazioari telefono-zenbakia eta gailu IDak zein diren, deirik aktibo dagoen eta deia zer zenbakirekin konektatuta dagoen zehazteko baimena ematen die aplikazioei."</string> + <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Gailuaren telefono-eginbideak erabiltzeko baimena ematen die aplikazioei. Baimen horrek aplikazioari telefono-zenbakia eta gailu IDak zein diren, deirik aktibo dagoen eta deia zer zenbakirekin konektatuta dagoen zehazteko baimena ematen die aplikazioei."</string> <string name="permlab_readBasicPhoneState" msgid="3214853233263871347">"irakurri oinarrizko egoera telefonikoa eta identitatea"</string> - <string name="permdesc_readBasicPhoneState" msgid="828185691675460520">"Gailuaren oinarrizko eginbide telefonikoak atzitzeko baimena ematen dio aplikazioari."</string> + <string name="permdesc_readBasicPhoneState" msgid="828185691675460520">"Gailuaren oinarrizko eginbide telefonikoak erabiltzeko baimena ematen dio aplikazioari."</string> <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"bideratu deiak sistemaren bidez"</string> <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"Deiak sistemaren bidez bideratzea baimentzen die aplikazioei, deien zerbitzua ahal bezain ona izan dadin."</string> <string name="permlab_callCompanionApp" msgid="3654373653014126884">"ikusi eta kontrolatu deiak sistemaren bidez."</string> @@ -484,7 +484,7 @@ <string name="permlab_acceptHandover" msgid="2925523073573116523">"jarraitu beste aplikazio batean hasitako deia"</string> <string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Beste aplikazio batean hasitako dei batekin jarraitzeko baimena ematen die aplikazioei."</string> <string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"irakurri telefono-zenbakiak"</string> - <string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Gailuaren telefono-zenbakiak atzitzeko baimena ematen die aplikazioei."</string> + <string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Gailuaren telefono-zenbakiak erabiltzeko baimena ematen die aplikazioei."</string> <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"mantendu piztuta autoko pantaila"</string> <string name="permlab_wakeLock" product="tablet" msgid="1527660973931694000">"eragotzi tableta inaktibo ezartzea"</string> <string name="permlab_wakeLock" product="tv" msgid="2856941418123343518">"Android TV gailua inaktibo ezar dadin eragotzi"</string> @@ -631,7 +631,7 @@ <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Sakatu hau aurpegi-eredua ezabatzeko eta, gero, gehitu aurpegia berriro"</string> <string name="face_setup_notification_title" msgid="8843461561970741790">"Konfiguratu aurpegi bidez desblokeatzeko eginbidea"</string> <string name="face_setup_notification_content" msgid="5463999831057751676">"Telefonoa desblokeatzeko, begira iezaiozu"</string> - <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Aurpegi bidez desblokeatzeko aukera erabiltzeko, aktibatu "<b>"kamera atzitzeko baimena"</b>" Ezarpenak > Pribatutasuna atalean"</string> + <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Aurpegi bidez desblokeatzeko aukera erabiltzeko, aktibatu "<b>"kamera erabiltzeko baimena"</b>" Ezarpenak > Pribatutasuna atalean"</string> <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Konfiguratu telefonoa desblokeatzeko modu gehiago"</string> <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Sakatu hau hatz-marka bat gehitzeko"</string> <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Hatz-marka bidez desblokeatzea"</string> @@ -1471,14 +1471,14 @@ <string name="ime_action_default" msgid="8265027027659800121">"Abiarazi"</string> <string name="dial_number_using" msgid="6060769078933953531">"Markatu zenbakia \n<xliff:g id="NUMBER">%s</xliff:g> erabilita"</string> <string name="create_contact_using" msgid="6200708808003692594">"Sortu kontaktu bat\n<xliff:g id="NUMBER">%s</xliff:g> erabilita"</string> - <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Aplikazio hauetako bat edo gehiago kontua orain eta etorkizunean atzitzeko baimena eskatzen ari dira."</string> + <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Aplikazio hauetako bat edo gehiago kontua orain eta etorkizunean erabiltzeko baimena eskatzen ari dira."</string> <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"Eskaera onartu nahi duzu?"</string> <string name="grant_permissions_header_text" msgid="3420736827804657201">"Sarbide-eskaera"</string> <string name="allow" msgid="6195617008611933762">"Eman baimena"</string> <string name="deny" msgid="6632259981847676572">"Ukatu"</string> <string name="permission_request_notification_title" msgid="1810025922441048273">"Baimena eskatu da"</string> <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Baimena eskatu da \n<xliff:g id="ACCOUNT">%s</xliff:g> konturako."</string> - <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"<xliff:g id="APP">%1$s</xliff:g> aplikazioak <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua atzitzeko baimena\neskatu du."</string> + <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"<xliff:g id="APP">%1$s</xliff:g> aplikazioak <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua erabiltzeko baimena\neskatu du."</string> <string name="forward_intent_to_owner" msgid="4620359037192871015">"Laneko profiletik kanpo ari zara aplikazioa erabiltzen"</string> <string name="forward_intent_to_work" msgid="3620262405636021151">"Laneko profilean ari zara aplikazioa erabiltzen"</string> <string name="input_method_binding_label" msgid="1166731601721983656">"Idazketa-metodoa"</string> @@ -2050,11 +2050,11 @@ <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DESINSTALATU"</string> <string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"IREKI, HALA ERE"</string> <string name="harmful_app_warning_title" msgid="8794823880881113856">"Aplikazio kaltegarri bat hauteman da"</string> - <string name="log_access_confirmation_title" msgid="2343578467290592708">"Gailuko erregistro guztiak atzitzeko baimena eman nahi diozu <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aplikazioari?"</string> + <string name="log_access_confirmation_title" msgid="2343578467290592708">"Gailuko erregistro guztiak erabiltzeko baimena eman nahi diozu <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aplikazioari?"</string> <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Eman behin erabiltzeko baimena"</string> <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ez eman baimenik"</string> - <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Gailuko erregistroetan gailuan gertatzen den guztia gordetzen da. Arazoak bilatu eta konpontzeko erabil ditzakete aplikazioek erregistro horiek.\n\nBaliteke erregistro batzuek kontuzko informazioa edukitzea. Beraz, eman gailuko erregistro guztiak atzitzeko baimena fidagarritzat jotzen dituzun aplikazioei bakarrik. \n\nNahiz eta gailuko erregistro guztiak atzitzeko baimena ez eman aplikazio honi, aplikazioak hari dagozkion erregistroak atzitu ahalko ditu. Gainera, baliteke gailuaren fabrikatzaileak gailuko erregistro edo datu batzuk atzitu ahal izatea."</string> - <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Gailuko erregistroetan gailuan gertatzen den guztia gordetzen da. Arazoak bilatu eta konpontzeko erabil ditzakete aplikazioek erregistro horiek.\n\nBaliteke erregistro batzuek kontuzko informazioa edukitzea. Beraz, eman gailuko erregistro guztiak atzitzeko baimena fidagarritzat jotzen dituzun aplikazioei bakarrik. \n\nNahiz eta gailuko erregistro guztiak atzitzeko baimena ez eman aplikazio honi, aplikazioak hari dagozkion erregistroak atzitu ahalko ditu. Gainera, baliteke gailuaren fabrikatzaileak gailuko erregistro edo datu batzuk atzitu ahal izatea.\n\nLortu informazio gehiago g.co/android/devicelogs helbidean."</string> + <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Gailuko erregistroetan gailuan gertatzen den guztia gordetzen da. Arazoak bilatu eta konpontzeko erabil ditzakete aplikazioek erregistro horiek.\n\nBaliteke erregistro batzuek kontuzko informazioa edukitzea. Beraz, eman gailuko erregistro guztiak erabiltzeko baimena fidagarritzat jotzen dituzun aplikazioei bakarrik. \n\nNahiz eta gailuko erregistro guztiak erabiltzeko baimena ez eman aplikazio honi, aplikazioak hari dagozkion erregistroak atzitu ahalko ditu. Gainera, baliteke gailuaren fabrikatzaileak gailuko erregistro edo datu batzuk atzitu ahal izatea."</string> + <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Gailuko erregistroetan gailuan gertatzen den guztia gordetzen da. Arazoak bilatu eta konpontzeko erabil ditzakete aplikazioek erregistro horiek.\n\nBaliteke erregistro batzuek kontuzko informazioa edukitzea. Beraz, eman gailuko erregistro guztiak erabiltzeko baimena fidagarritzat jotzen dituzun aplikazioei bakarrik. \n\nNahiz eta gailuko erregistro guztiak erabiltzeko baimena ez eman aplikazio honi, aplikazioak hari dagozkion erregistroak atzitu ahalko ditu. Gainera, baliteke gailuaren fabrikatzaileak gailuko erregistro edo datu batzuk atzitu ahal izatea.\n\nLortu informazio gehiago g.co/android/devicelogs helbidean."</string> <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ez erakutsi berriro"</string> <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> aplikazioak <xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakutsi nahi ditu"</string> <string name="screenshot_edit" msgid="7408934887203689207">"Editatu"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 279560907928..6ca95b3281e5 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -53,7 +53,7 @@ <string name="enablePin" msgid="2543771964137091212">"Opération infructueuse. Activez le verrouillage SIM/RUIM."</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584"> <item quantity="one">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM soit verrouillée.</item> - <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item> + <item quantity="many">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM soit verrouillée.</item> <item quantity="other">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM soit verrouillée.</item> </plurals> <string name="imei" msgid="2157082351232630390">"Code IIEM"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 0888f2f9a8dd..815ae1be8dc1 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -53,7 +53,7 @@ <string name="enablePin" msgid="2543771964137091212">"Échec de l\'opération. Veuillez activer le verrouillage de la carte SIM/RUIM."</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584"> <item quantity="one">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM ne soit verrouillée.</item> - <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item> + <item quantity="many">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM ne soit verrouillée.</item> <item quantity="other">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM ne soit verrouillée.</item> </plurals> <string name="imei" msgid="2157082351232630390">"Code IMEI"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index d1d7d3b4ca39..304d21226de6 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -52,7 +52,7 @@ <string name="needPuk2" msgid="7032612093451537186">"Digita il PUK2 per sbloccare la SIM."</string> <string name="enablePin" msgid="2543771964137091212">"Operazione non riuscita; attiva blocco SIM/RUIM."</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584"> - <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item> + <item quantity="many">Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM venga bloccata.</item> <item quantity="other">Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM venga bloccata.</item> <item quantity="one">Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM venga bloccata.</item> </plurals> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 524ad37a6422..7886d2b471b2 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -53,7 +53,7 @@ <string name="enablePin" msgid="2543771964137091212">"Falha. Ative o bloqueio do chip/R-UIM."</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584"> <item quantity="one">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item> - <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item> + <item quantity="many">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item> <item quantity="other">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item> </plurals> <string name="imei" msgid="2157082351232630390">"IMEI"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index c2cf7abc1642..561e47eb5cfa 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -52,7 +52,7 @@ <string name="needPuk2" msgid="7032612093451537186">"Introduza o PUK2 para desbloquear o cartão SIM."</string> <string name="enablePin" msgid="2543771964137091212">"Ação sem êxito. Ative o bloqueio do SIM/RUIM."</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584"> - <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item> + <item quantity="many">Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar bloqueado.</item> <item quantity="other">Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar bloqueado.</item> <item quantity="one">Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar bloqueado.</item> </plurals> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 524ad37a6422..7886d2b471b2 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -53,7 +53,7 @@ <string name="enablePin" msgid="2543771964137091212">"Falha. Ative o bloqueio do chip/R-UIM."</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584"> <item quantity="one">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item> - <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item> + <item quantity="many">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item> <item quantity="other">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item> </plurals> <string name="imei" msgid="2157082351232630390">"IMEI"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index cf3677e85323..c7658177e2ca 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -598,7 +598,7 @@ <string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Слишком светло."</string> <string name="fingerprint_acquired_power_press" msgid="3107864151278434961">"Вы нажали кнопку питания."</string> <string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Попробуйте изменить положение пальца."</string> - <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Каждый раз немного меняйте положение пальца."</string> + <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Каждый раз немного меняйте положение пальца"</string> <string-array name="fingerprint_acquired_vendor"> </string-array> <string name="fingerprint_error_not_match" msgid="4599441812893438961">"Отпечаток не распознан."</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 60fae7e9daa6..2f3951f2f3f5 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -596,7 +596,7 @@ <string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"光线太亮"</string> <string name="fingerprint_acquired_power_press" msgid="3107864151278434961">"检测到按下“电源”按钮的操作"</string> <string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"请尝试调整指纹"</string> - <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"请在每次放手指时略微更改手指的位置"</string> + <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"每次放手指时,请略微变换手指的位置"</string> <string-array name="fingerprint_acquired_vendor"> </string-array> <string name="fingerprint_error_not_match" msgid="4599441812893438961">"未能识别指纹"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index dffd1cc9e217..dafa0ad7989f 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -6084,6 +6084,12 @@ different from the home screen wallpaper. --> <bool name="config_independentLockscreenLiveWallpaper">false</bool> + <!-- Whether the vendor power press code need to be mapped. --> + <bool name="config_powerPressMapping">false</bool> + + <!-- Power press vendor code. --> + <integer name="config_powerPressCode">-1</integer> + <!-- Whether to show weather on the lock screen by default. --> <bool name="config_lockscreenWeatherEnabledByDefault">false</bool> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index ba541839ee0c..2091c0502b6f 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -975,6 +975,11 @@ <!-- Description for the capability of an accessibility service to take screenshot. [CHAR LIMIT=NONE] --> <string name="capability_desc_canTakeScreenshot">Can take a screenshot of the display.</string> + <!-- Dream --> + + <!-- The title to use when a dream is opened in preview mode. [CHAR LIMIT=NONE] --> + <string name="dream_preview_title">Preview, <xliff:g id="dream_name" example="Clock">%1$s</xliff:g></string> + <!-- Permissions --> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ad5b9c0e0f54..591ba5feeee9 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2655,6 +2655,8 @@ <java-symbol type="integer" name="config_sideFpsToastTimeout"/> <java-symbol type="integer" name="config_sidefpsSkipWaitForPowerAcquireMessage"/> <java-symbol type="integer" name="config_sidefpsSkipWaitForPowerVendorAcquireMessage"/> + <java-symbol type="integer" name="config_powerPressCode"/> + <java-symbol type="bool" name="config_powerPressMapping"/> <!-- Clickable toast used during sidefps enrollment --> <java-symbol type="layout" name="side_fps_toast" /> @@ -4285,6 +4287,8 @@ <java-symbol type="string" name="capability_desc_canTakeScreenshot" /> <java-symbol type="string" name="capability_title_canTakeScreenshot" /> + <java-symbol type="string" name="dream_preview_title" /> + <java-symbol type="string" name="config_servicesExtensionPackage" /> <!-- For app process exit info tracking --> diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java index dc04220a0a11..c92ae2c98f9a 100644 --- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java +++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java @@ -457,6 +457,7 @@ public class AccessibilityShortcutControllerTest { } } + @Test public void getFrameworkFeatureMap_containsExpectedDefaultKeys() { final Map<ComponentName, AccessibilityShortcutController.ToggleableFrameworkFeatureInfo> frameworkFeatureMap = @@ -489,6 +490,7 @@ public class AccessibilityShortcutControllerTest { assertFalse(frameworkFeatureMap.containsKey(ONE_HANDED_COMPONENT_NAME)); } + @Test public void testOnAccessibilityShortcut_forServiceWithNoSummary_doesNotCrash() throws Exception { configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java index 52feac5a585a..4c9b2b7f5dd6 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java @@ -360,6 +360,7 @@ public class BatteryStatsNoteTest extends TestCase { // map of ActivityManager process states and how long to simulate run time in each state Map<Integer, Integer> stateRuntimeMap = new HashMap<Integer, Integer>(); stateRuntimeMap.put(ActivityManager.PROCESS_STATE_TOP, 1111); + stateRuntimeMap.put(ActivityManager.PROCESS_STATE_BOUND_TOP, 7382); stateRuntimeMap.put(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE, 1234); stateRuntimeMap.put(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 2468); stateRuntimeMap.put(ActivityManager.PROCESS_STATE_TOP_SLEEPING, 7531); @@ -396,7 +397,8 @@ public class BatteryStatsNoteTest extends TestCase { actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE, elapsedTimeUs, STATS_SINCE_CHARGED); - expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); + expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) + + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE); assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs); actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING, @@ -406,8 +408,7 @@ public class BatteryStatsNoteTest extends TestCase { actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND, elapsedTimeUs, STATS_SINCE_CHARGED); - expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) - + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE); + expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs); actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND, @@ -415,7 +416,8 @@ public class BatteryStatsNoteTest extends TestCase { expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_BACKUP) + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_SERVICE) - + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_RECEIVER); + + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_RECEIVER) + + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_BOUND_TOP); assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs); actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_CACHED, diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java index 354b93709976..274286135174 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java @@ -78,9 +78,9 @@ public class BatteryUsageStatsProviderTest { batteryUsageStats.getUidBatteryConsumers(); final UidBatteryConsumer uidBatteryConsumer = uidBatteryConsumers.get(0); assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND)) - .isEqualTo(60 * MINUTE_IN_MS); + .isEqualTo(20 * MINUTE_IN_MS); assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND)) - .isEqualTo(10 * MINUTE_IN_MS); + .isEqualTo(40 * MINUTE_IN_MS); assertThat(uidBatteryConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO)) .isWithin(PRECISION).of(2.0); assertThat( @@ -121,22 +121,44 @@ public class BatteryUsageStatsProviderTest { private BatteryStatsImpl prepareBatteryStats() { BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); - batteryStats.noteActivityResumedLocked(APP_UID, - 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); - batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_TOP, - 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); - batteryStats.noteActivityPausedLocked(APP_UID, - 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS); - batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_SERVICE, - 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS); - batteryStats.noteUidProcessStateLocked(APP_UID, - ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, - 40 * MINUTE_IN_MS, 40 * MINUTE_IN_MS); - batteryStats.noteUidProcessStateLocked(APP_UID, - ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE, - 50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS); - batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY, - 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); + mStatsRule.setTime(10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); + synchronized (batteryStats) { + batteryStats.noteActivityResumedLocked(APP_UID); + } + + mStatsRule.setTime(10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); + synchronized (batteryStats) { + batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_TOP); + } + mStatsRule.setTime(30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS); + synchronized (batteryStats) { + batteryStats.noteActivityPausedLocked(APP_UID); + } + mStatsRule.setTime(30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS); + synchronized (batteryStats) { + batteryStats.noteUidProcessStateLocked(APP_UID, + ActivityManager.PROCESS_STATE_SERVICE); + } + mStatsRule.setTime(40 * MINUTE_IN_MS, 40 * MINUTE_IN_MS); + synchronized (batteryStats) { + batteryStats.noteUidProcessStateLocked(APP_UID, + ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); + } + mStatsRule.setTime(50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS); + synchronized (batteryStats) { + batteryStats.noteUidProcessStateLocked(APP_UID, + ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE); + } + mStatsRule.setTime(60 * MINUTE_IN_MS, 60 * MINUTE_IN_MS); + synchronized (batteryStats) { + batteryStats.noteUidProcessStateLocked(APP_UID, + ActivityManager.PROCESS_STATE_BOUND_TOP); + } + mStatsRule.setTime(70 * MINUTE_IN_MS, 70 * MINUTE_IN_MS); + synchronized (batteryStats) { + batteryStats.noteUidProcessStateLocked(APP_UID, + ActivityManager.PROCESS_STATE_CACHED_EMPTY); + } batteryStats.noteFlashlightOnLocked(APP_UID, 1000, 1000); batteryStats.noteFlashlightOffLocked(APP_UID, 5000, 5000); diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java index fa1730728afb..d39d4b466143 100644 --- a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java +++ b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java @@ -412,11 +412,11 @@ public final class RequiresPermissionChecker extends BugChecker private static ParsedRequiresPermission parseRequiresPermissionRecursively( MethodInvocationTree tree, VisitorState state) { - if (ENFORCE_VIA_CONTEXT.matches(tree, state)) { + if (ENFORCE_VIA_CONTEXT.matches(tree, state) && tree.getArguments().size() > 0) { final ParsedRequiresPermission res = new ParsedRequiresPermission(); res.allOf.add(String.valueOf(ASTHelpers.constValue(tree.getArguments().get(0)))); return res; - } else if (ENFORCE_VIA_CHECKER.matches(tree, state)) { + } else if (ENFORCE_VIA_CHECKER.matches(tree, state) && tree.getArguments().size() > 1) { final ParsedRequiresPermission res = new ParsedRequiresPermission(); res.allOf.add(String.valueOf(ASTHelpers.constValue(tree.getArguments().get(1)))); return res; diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java index 388988e5e9bd..38831b193610 100644 --- a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java +++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java @@ -415,4 +415,27 @@ public class RequiresPermissionCheckerTest { "}") .doTest(); } + + @Test + public void testInvalidFunctions() { + compilationHelper + .addSourceFile("/android/annotation/RequiresPermission.java") + .addSourceFile("/android/annotation/SuppressLint.java") + .addSourceFile("/android/content/Context.java") + .addSourceLines("Example.java", + "import android.annotation.RequiresPermission;", + "import android.annotation.SuppressLint;", + "import android.content.Context;", + "class Foo extends Context {", + " private static final String RED = \"red\";", + " public void checkPermission() {", + " }", + " @RequiresPermission(RED)", + " // BUG: Diagnostic contains:", + " public void exampleScoped(Context context) {", + " checkPermission();", + " }", + "}") + .doTest(); + } } diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar Binary files differindex 68523209c9cc..c3b6916121d0 100644 --- a/libs/WindowManager/Jetpack/window-extensions-release.aar +++ b/libs/WindowManager/Jetpack/window-extensions-release.aar diff --git a/libs/WindowManager/Shell/res/drawable/caption_close_button.xml b/libs/WindowManager/Shell/res/drawable/caption_close_button.xml new file mode 100644 index 000000000000..e258564c70f7 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/caption_close_button.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="32.0dp" + android:height="32.0dp" + android:viewportWidth="32.0" + android:viewportHeight="32.0" +> + <group android:scaleX="0.5" + android:scaleY="0.5" + android:translateY="4.0"> + <path + android:fillColor="#FFFF0000" + android:pathData="M12.45,38.35 L9.65,35.55 21.2,24 9.65,12.45 12.45,9.65 24,21.2 35.55,9.65 38.35,12.45 26.8,24 38.35,35.55 35.55,38.35 24,26.8Z"/> + </group> +</vector> diff --git a/libs/WindowManager/Shell/res/drawable/caption_collapse_menu_button.xml b/libs/WindowManager/Shell/res/drawable/caption_collapse_menu_button.xml new file mode 100644 index 000000000000..166552dcb9e8 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/caption_collapse_menu_button.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" +> + <group android:scaleX="1.25" + android:scaleY="1.75" + android:translateY="6.0"> + <path + android:fillColor="@android:color/black" + android:pathData="M10.3937 6.93935L11.3337 5.99935L6.00033 0.666016L0.666992 5.99935L1.60699 6.93935L6.00033 2.55268"/> + </group> +</vector> diff --git a/libs/WindowManager/Shell/res/drawable/caption_screenshot_button.xml b/libs/WindowManager/Shell/res/drawable/caption_screenshot_button.xml new file mode 100644 index 000000000000..7c86888f5226 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/caption_screenshot_button.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="32.0dp" + android:height="32.0dp" + android:viewportWidth="32.0" + android:viewportHeight="32.0" +> + <group android:scaleX="0.5" + android:scaleY="0.5" + android:translateY="4.0"> + <path + android:fillColor="@android:color/black" + android:pathData="M10,38V28.35H13V35H19.65V38ZM10,19.65V10H19.65V13H13V19.65ZM28.35,38V35H35V28.35H38V38ZM35,19.65V13H28.35V10H38V19.65Z"/> + </group> +</vector> diff --git a/libs/WindowManager/Shell/res/drawable/caption_select_button.xml b/libs/WindowManager/Shell/res/drawable/caption_select_button.xml new file mode 100644 index 000000000000..8c60c8407174 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/caption_select_button.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="32.0dp" + android:height="32.0dp" + android:viewportWidth="32.0" + android:viewportHeight="32.0" +> + <group + android:translateX="4.0" + android:translateY="6.0"> + <path + android:fillColor="@android:color/black" + android:pathData="M13.7021 12.5833L16.5676 15.5L15.426 16.7333L12.526 13.8333L10.4426 15.9167V10.5H15.9176L13.7021 12.5833ZM13.8343 3.83333H15.501V5.5H13.8343V3.83333ZM15.501 2.16667H13.8343V0.566667C14.751 0.566667 15.501 1.33333 15.501 2.16667ZM10.501 0.5H12.1676V2.16667H10.501V0.5ZM13.8343 7.16667H15.501V8.83333H13.8343V7.16667ZM5.50098 15.5H3.83431V13.8333H5.50098V15.5ZM2.16764 5.5H0.500977V3.83333H2.16764V5.5ZM2.16764 0.566667V2.16667H0.500977C0.500977 1.33333 1.33431 0.566667 2.16764 0.566667ZM2.16764 12.1667H0.500977V10.5H2.16764V12.1667ZM5.50098 2.16667H3.83431V0.5H5.50098V2.16667ZM8.83431 2.16667H7.16764V0.5H8.83431V2.16667ZM8.83431 15.5H7.16764V13.8333H8.83431V15.5ZM2.16764 8.83333H0.500977V7.16667H2.16764V8.83333ZM2.16764 15.5667C1.25098 15.5667 0.500977 14.6667 0.500977 13.8333H2.16764V15.5667Z"/> + </group> +</vector> diff --git a/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml index c9f262398f68..27e0b184f427 100644 --- a/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml +++ b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml @@ -17,9 +17,10 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24" - android:viewportHeight="24"> + android:viewportHeight="24" + android:tint="@color/decor_button_dark_color"> <group android:translateY="8.0"> <path - android:fillColor="@android:color/black" android:pathData="M3,5V3H21V5Z"/> + android:fillColor="@android:color/white" android:pathData="M3,5V3H21V5Z"/> </group> </vector> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml index 416287d2cbb3..9167382d0898 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml @@ -18,4 +18,5 @@ xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@android:color/white" /> <corners android:radius="20dp" /> + <stroke android:width="1dp" android:color="#b3b3b3"/> </shape> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_title.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_title.xml index 53a8bb18537c..ef3006042261 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_title.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_title.xml @@ -15,6 +15,8 @@ ~ limitations under the License. --> <shape android:shape="rectangle" + android:tintMode="multiply" + android:tint="@color/decor_title_color" xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@android:color/white" /> </shape> diff --git a/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml b/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml index 29945937788b..b3f8e801bac4 100644 --- a/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml +++ b/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml @@ -25,12 +25,10 @@ android:fillAlpha="0.8" android:pathData="M0,24 a24,24 0 1,0 48,0 a24,24 0 1,0 -48,0"/> <group - android:scaleX="0.8" - android:scaleY="0.8" - android:translateX="10" - android:translateY="10"> + android:translateX="12" + android:translateY="12"> <path - android:pathData="M0,36V24.5H3V30.85L10.4,23.45L12.55,25.6L5.15,33H11.5V36H0ZM24.5,36V33H30.85L23.5,25.65L25.65,23.5L33,30.85V24.5H36V36H24.5ZM10.35,12.5L3,5.15V11.5H0V0H11.5V3H5.15L12.5,10.35L10.35,12.5ZM25.65,12.5L23.5,10.35L30.85,3H24.5V0H36V11.5H33V5.15L25.65,12.5Z" - android:fillColor="@color/compat_controls_text"/> + android:fillColor="@color/compat_controls_text" + android:pathData="M3,21V15H5V17.6L8.1,14.5L9.5,15.9L6.4,19H9V21ZM15,21V19H17.6L14.5,15.9L15.9,14.5L19,17.6V15H21V21ZM8.1,9.5 L5,6.4V9H3V3H9V5H6.4L9.5,8.1ZM15.9,9.5 L14.5,8.1 17.6,5H15V3H21V9H19V6.4Z"/> </group> </vector> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml index 8b4792acba3e..f6e3f2edfa14 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml @@ -1,49 +1,129 @@ <?xml version="1.0" encoding="utf-8"?> - <!-- - ~ 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. - --> +<!-- + ~ 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. + --> <com.android.wm.shell.windowdecor.WindowDecorLinearLayout -xmlns:android="http://schemas.android.com/apk/res/android" -android:id="@+id/handle_menu" -android:layout_width="wrap_content" -android:layout_height="wrap_content" -android:gravity="center_horizontal" -android:background="@drawable/desktop_mode_decor_menu_background"> - <Button - style="@style/CaptionButtonStyle" - android:id="@+id/fullscreen_button" - android:contentDescription="@string/fullscreen_text" - android:background="@drawable/caption_fullscreen_button"/> - <Button - style="@style/CaptionButtonStyle" - android:id="@+id/split_screen_button" - android:contentDescription="@string/split_screen_text" - android:background="@drawable/caption_split_screen_button"/> - <Button - style="@style/CaptionButtonStyle" - android:id="@+id/floating_button" - android:contentDescription="@string/float_button_text" - android:background="@drawable/caption_floating_button"/> - <Button - style="@style/CaptionButtonStyle" - android:id="@+id/desktop_button" - android:contentDescription="@string/desktop_text" - android:background="@drawable/caption_desktop_button"/> - <Button - style="@style/CaptionButtonStyle" - android:id="@+id/more_button" - android:contentDescription="@string/more_button_text" - android:background="@drawable/caption_more_button"/> + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/handle_menu" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:background="@drawable/desktop_mode_decor_menu_background" + android:elevation="@dimen/caption_menu_elevation" + android:divider="?android:attr/dividerHorizontal" + android:showDividers="middle" + android:dividerPadding="18dip"> + <RelativeLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + <ImageView + android:id="@+id/application_icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_margin="12dp" + android:contentDescription="@string/app_icon_text" + android:layout_alignParentStart="true" + android:layout_centerVertical="true"/> + <TextView + android:id="@+id/application_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toEndOf="@+id/application_icon" + android:layout_toStartOf="@+id/collapse_menu_button" + android:textColor="#FF000000" + android:layout_centerVertical="true"/> + <Button + android:id="@+id/collapse_menu_button" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginEnd="10dp" + android:contentDescription="@string/collapse_menu_text" + android:layout_alignParentEnd="true" + android:background="@drawable/caption_collapse_menu_button" + android:layout_centerVertical="true"/> + </RelativeLayout> + <LinearLayout + android:id="@+id/windowing_mode_buttons" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal"> + <Space + android:layout_width="0dp" + android:layout_height="1dp" + android:layout_weight="0.5" /> + <Button + style="@style/CaptionWindowingButtonStyle" + android:id="@+id/fullscreen_button" + android:contentDescription="@string/fullscreen_text" + android:background="@drawable/caption_fullscreen_button"/> + <Space + android:layout_width="0dp" + android:layout_height="1dp" + android:layout_weight="1" /> + <Button + style="@style/CaptionWindowingButtonStyle" + android:id="@+id/split_screen_button" + android:contentDescription="@string/split_screen_text" + android:background="@drawable/caption_split_screen_button"/> + <Space + android:layout_width="0dp" + android:layout_height="1dp" + android:layout_weight="1" /> + <Button + style="@style/CaptionWindowingButtonStyle" + android:id="@+id/floating_button" + android:contentDescription="@string/float_button_text" + android:background="@drawable/caption_floating_button"/> + <Space + android:layout_width="0dp" + android:layout_height="1dp" + android:layout_weight="1" /> + <Button + style="@style/CaptionWindowingButtonStyle" + android:id="@+id/desktop_button" + android:contentDescription="@string/desktop_text" + android:background="@drawable/caption_desktop_button"/> + <Space + android:layout_width="0dp" + android:layout_height="1dp" + android:layout_weight="0.5" /> + + </LinearLayout> + <LinearLayout + android:id="@+id/menu_buttons_misc" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + <Button + style="@style/CaptionMenuButtonStyle" + android:id="@+id/screenshot_button" + android:contentDescription="@string/screenshot_text" + android:text="@string/screenshot_text" + android:drawableStart="@drawable/caption_screenshot_button"/> + <Button + style="@style/CaptionMenuButtonStyle" + android:id="@+id/select_button" + android:contentDescription="@string/select_text" + android:text="@string/select_text" + android:drawableStart="@drawable/caption_select_button"/> + <Button + style="@style/CaptionMenuButtonStyle" + android:id="@+id/close_button" + android:contentDescription="@string/close_text" + android:text="@string/close_text" + android:drawableStart="@drawable/caption_close_button" + android:textColor="#FFFF0000"/> + </LinearLayout> </com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor.xml index da31a46713df..29cf1512e2e5 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor.xml @@ -22,9 +22,20 @@ android:gravity="center_horizontal" android:background="@drawable/desktop_mode_decor_title"> <Button + style="@style/CaptionButtonStyle" + android:id="@+id/back_button" + android:contentDescription="@string/back_button_text" + android:background="@drawable/decor_back_button_dark"/> + <Button android:id="@+id/caption_handle" android:layout_width="128dp" android:layout_height="32dp" + android:layout_margin="5dp" android:contentDescription="@string/handle_text" android:background="@drawable/decor_handle_dark"/> + <Button + style="@style/CaptionButtonStyle" + android:id="@+id/close_window" + android:contentDescription="@string/close_button_text" + android:background="@drawable/decor_close_button_dark"/> </com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml index 33e6aa6e487a..26246fcee52b 100644 --- a/libs/WindowManager/Shell/res/values-af/strings.xml +++ b/libs/WindowManager/Shell/res/values-af/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bo 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Bo 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Volskerm onder"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Gebruik eenhandmodus"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Swiep van die onderkant van die skerm af op of tik enige plek bo die program om uit te gaan"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Begin eenhandmodus"</string> diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml index 4b7a5ecb6c6f..7f0a3ab2c070 100644 --- a/libs/WindowManager/Shell/res/values-am/strings.xml +++ b/libs/WindowManager/Shell/res/values-am/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ከላይ 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ከላይ 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"የታች ሙሉ ማያ ገጽ"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"ባለአንድ እጅ ሁነታን በመጠቀም ላይ"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"ለመውጣት ከማያው ግርጌ ወደ ላይ ይጥረጉ ወይም ከመተግበሪያው በላይ ማንኛውም ቦታ ላይ መታ ያድርጉ"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ባለአንድ እጅ ሁነታ ጀምር"</string> diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml index 851d2d1f1bd2..7f81e50e72fa 100644 --- a/libs/WindowManager/Shell/res/values-ar/strings.xml +++ b/libs/WindowManager/Shell/res/values-ar/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ضبط حجم النافذة العلوية ليكون ٥٠%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ضبط حجم النافذة العلوية ليكون ٣٠%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"عرض النافذة السفلية بملء الشاشة"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"استخدام وضع \"التصفح بيد واحدة\""</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"للخروج، مرِّر سريعًا من أسفل الشاشة إلى أعلاها أو انقر في أي مكان فوق التطبيق."</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"بدء وضع \"التصفح بيد واحدة\""</string> diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml index f8c87aebd56a..505ca96a3c73 100644 --- a/libs/WindowManager/Shell/res/values-as/strings.xml +++ b/libs/WindowManager/Shell/res/values-as/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ স্ক্ৰীনখন ৫০% কৰক"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"শীর্ষ স্ক্ৰীনখন ৩০% কৰক"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"তলৰ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"এখন হাতেৰে ব্যৱহাৰ কৰা ম’ড ব্যৱহাৰ কৰা"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"বাহিৰ হ’বলৈ স্ক্ৰীনখনৰ একেবাৰে তলৰ পৰা ওপৰলৈ ছোৱাইপ কৰক অথবা এপ্টোৰ ওপৰত যিকোনো ঠাইত টিপক"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"এখন হাতেৰে ব্যৱহাৰ কৰা ম\'ডটো আৰম্ভ কৰক"</string> diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml index 10663ee30553..0d754bae12fc 100644 --- a/libs/WindowManager/Shell/res/values-az/strings.xml +++ b/libs/WindowManager/Shell/res/values-az/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yuxarı 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Yuxarı 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Aşağı tam ekran"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Birəlli rejim istifadəsi"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Çıxmaq üçün ekranın aşağısından yuxarıya doğru sürüşdürün və ya tətbiqin yuxarısında istənilən yerə toxunun"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Birəlli rejim başlasın"</string> diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml index 47e661c531a2..46d9f2b028d7 100644 --- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml +++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gornji ekran 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gornji ekran 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Režim celog ekrana za donji ekran"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Korišćenje režima jednom rukom"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Da biste izašli, prevucite nagore od dna ekrana ili dodirnite bilo gde iznad aplikacije"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Pokrenite režim jednom rukom"</string> diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml index d2a790ae0604..31d0484476cd 100644 --- a/libs/WindowManager/Shell/res/values-be/strings.xml +++ b/libs/WindowManager/Shell/res/values-be/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхні экран – 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Верхні экран – 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ніжні экран – поўнаэкранны рэжым"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Выкарыстоўваецца рэжым кіравання адной рукой"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Каб выйсці, правядзіце па экране пальцам знізу ўверх або націсніце ў любым месцы над праграмай"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Запусціць рэжым кіравання адной рукой"</string> diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml index cb76e0ac3911..08fe3656891c 100644 --- a/libs/WindowManager/Shell/res/values-bg/strings.xml +++ b/libs/WindowManager/Shell/res/values-bg/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горен екран: 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Горен екран: 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Долен екран: Показване на цял екран"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Използване на режима за работа с една ръка"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"За изход прекарайте пръст нагоре от долната част на екрана или докоснете произволно място над приложението"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Стартиране на режима за работа с една ръка"</string> diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml index f3d740b633e4..ac0daa0f97cb 100644 --- a/libs/WindowManager/Shell/res/values-bn/strings.xml +++ b/libs/WindowManager/Shell/res/values-bn/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ ৫০%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"শীর্ষ ৩০%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"নীচের অংশ নিয়ে পূর্ণ স্ক্রিন"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"\'এক হাতে ব্যবহার করার মোড\'-এর ব্যবহার"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"বেরিয়ে আসার জন্য, স্ক্রিনের নিচ থেকে উপরের দিকে সোয়াইপ করুন অথবা অ্যাপ আইকনের উপরে যেকোনও জায়গায় ট্যাপ করুন"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"\'এক হাতে ব্যবহার করার মোড\' শুরু করুন"</string> diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml index 2405b2aa5180..745e6fc06b9b 100644 --- a/libs/WindowManager/Shell/res/values-bs/strings.xml +++ b/libs/WindowManager/Shell/res/values-bs/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gore 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gore 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Donji ekran kao cijeli ekran"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Korištenje načina rada jednom rukom"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Da izađete, prevucite s dna ekrana prema gore ili dodirnite bilo gdje iznad aplikacije"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Započinjanje načina rada jednom rukom"</string> diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml index 965a72d79c6b..727c31913516 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings.xml @@ -22,7 +22,7 @@ <string name="pip_phone_settings" msgid="5468987116750491918">"Configuració"</string> <string name="pip_phone_enter_split" msgid="7042877263880641911">"Entra al mode de pantalla dividida"</string> <string name="pip_menu_title" msgid="5393619322111827096">"Menú"</string> - <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> està en pantalla en pantalla"</string> + <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> està en mode d\'imatge sobre imatge"</string> <string name="pip_notification_message" msgid="8854051911700302620">"Si no vols que <xliff:g id="NAME">%s</xliff:g> utilitzi aquesta funció, toca per obrir la configuració i desactiva-la."</string> <string name="pip_play" msgid="3496151081459417097">"Reprodueix"</string> <string name="pip_pause" msgid="690688849510295232">"Posa en pausa"</string> @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Pantalla superior al 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Pantalla superior al 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"S\'està utilitzant el mode d\'una mà"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Per sortir, llisca cap amunt des de la part inferior de la pantalla o toca qualsevol lloc a sobre de l\'aplicació"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Inicia el mode d\'una mà"</string> diff --git a/libs/WindowManager/Shell/res/values-ca/strings_tv.xml b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml index 94ba0db7e978..daa8c1d1d812 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings_tv.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml @@ -17,7 +17,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="notification_channel_tv_pip" msgid="2576686079160402435">"Pantalla en pantalla"</string> + <string name="notification_channel_tv_pip" msgid="2576686079160402435">"Imatge sobre imatge"</string> <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa sense títol)"</string> <string name="pip_close" msgid="2955969519031223530">"Tanca"</string> <string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string> @@ -25,7 +25,7 @@ <string name="pip_expand" msgid="1051966011679297308">"Desplega"</string> <string name="pip_collapse" msgid="3903295106641385962">"Replega"</string> <string name="pip_edu_text" msgid="3672999496647508701">" Prem dos cops "<annotation icon="home_icon">" INICI "</annotation>" per accedir als controls"</string> - <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menú de pantalla en pantalla."</string> + <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Menú d\'imatge sobre imatge."</string> <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mou cap a l\'esquerra"</string> <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mou cap a la dreta"</string> <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mou cap amunt"</string> diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml index 8fa64fb25afb..395e12caf6e1 100644 --- a/libs/WindowManager/Shell/res/values-cs/strings.xml +++ b/libs/WindowManager/Shell/res/values-cs/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % nahoře"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % nahoře"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Dolní část na celou obrazovku"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Používání režimu jedné ruky"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Režim ukončíte, když přejedete prstem z dolní části obrazovky nahoru nebo klepnete kamkoli nad aplikaci"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Spustit režim jedné ruky"</string> diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml index e3da6e069486..5087c13be462 100644 --- a/libs/WindowManager/Shell/res/values-da/strings.xml +++ b/libs/WindowManager/Shell/res/values-da/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Øverste 50 %"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Øverste 30 %"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Vis nederste del i fuld skærm"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Brug af enhåndstilstand"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Du kan afslutte ved at stryge opad fra bunden af skærmen eller trykke et vilkårligt sted over appen"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Start enhåndstilstand"</string> diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index 39d7bab9e640..e97f0687ca3d 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % oben"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % oben"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Vollbild unten"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Einhandmodus wird verwendet"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Wenn du die App schließen möchtest, wische vom unteren Rand des Displays nach oben oder tippe auf eine beliebige Stelle oberhalb der App"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Einhandmodus starten"</string> diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml index 4f4265adfc32..df82625674f1 100644 --- a/libs/WindowManager/Shell/res/values-el/strings.xml +++ b/libs/WindowManager/Shell/res/values-el/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Πάνω 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Πάνω 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Κάτω πλήρης οθόνη"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Χρήση λειτουργίας ενός χεριού"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Για έξοδο, σύρετε προς τα πάνω από το κάτω μέρος της οθόνης ή πατήστε οπουδήποτε πάνω από την εφαρμογή."</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Έναρξη λειτουργίας ενός χεριού"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml index e29b01b392ba..b1c9ba8203ee 100644 --- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml @@ -47,6 +47,10 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Top 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Bottom full screen"</string> + <string name="accessibility_split_left" msgid="1713683765575562458">"Split left"</string> + <string name="accessibility_split_right" msgid="8441001008181296837">"Split right"</string> + <string name="accessibility_split_top" msgid="2789329702027147146">"Split top"</string> + <string name="accessibility_split_bottom" msgid="8694551025220868191">"Split bottom"</string> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Using one-handed mode"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Start one-handed mode"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml index 9228c59320f1..4aa22116b256 100644 --- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml @@ -47,6 +47,10 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Top 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Bottom full screen"</string> + <string name="accessibility_split_left" msgid="1713683765575562458">"Split left"</string> + <string name="accessibility_split_right" msgid="8441001008181296837">"Split right"</string> + <string name="accessibility_split_top" msgid="2789329702027147146">"Split top"</string> + <string name="accessibility_split_bottom" msgid="8694551025220868191">"Split bottom"</string> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Using one-handed mode"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Start one-handed mode"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml index e29b01b392ba..b1c9ba8203ee 100644 --- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml @@ -47,6 +47,10 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Top 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Bottom full screen"</string> + <string name="accessibility_split_left" msgid="1713683765575562458">"Split left"</string> + <string name="accessibility_split_right" msgid="8441001008181296837">"Split right"</string> + <string name="accessibility_split_top" msgid="2789329702027147146">"Split top"</string> + <string name="accessibility_split_bottom" msgid="8694551025220868191">"Split bottom"</string> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Using one-handed mode"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Start one-handed mode"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml index e29b01b392ba..b1c9ba8203ee 100644 --- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml @@ -47,6 +47,10 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Top 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Bottom full screen"</string> + <string name="accessibility_split_left" msgid="1713683765575562458">"Split left"</string> + <string name="accessibility_split_right" msgid="8441001008181296837">"Split right"</string> + <string name="accessibility_split_top" msgid="2789329702027147146">"Split top"</string> + <string name="accessibility_split_bottom" msgid="8694551025220868191">"Split bottom"</string> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Using one-handed mode"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Start one-handed mode"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml index cf231145f906..265849cd4978 100644 --- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml @@ -47,6 +47,10 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Top 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Bottom full screen"</string> + <string name="accessibility_split_left" msgid="1713683765575562458">"Split left"</string> + <string name="accessibility_split_right" msgid="8441001008181296837">"Split right"</string> + <string name="accessibility_split_top" msgid="2789329702027147146">"Split top"</string> + <string name="accessibility_split_bottom" msgid="8694551025220868191">"Split bottom"</string> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Using one-handed mode"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Start one-handed mode"</string> diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml index a147be3e48a5..1196aaf8ffb9 100644 --- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml +++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior: 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Superior: 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Cómo usar el modo de una mano"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para salir, desliza el dedo hacia arriba desde la parte inferior de la pantalla o presiona cualquier parte arriba de la app"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar el modo de una mano"</string> diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml index 8c4887694cf6..c3c832b4943f 100644 --- a/libs/WindowManager/Shell/res/values-es/strings.xml +++ b/libs/WindowManager/Shell/res/values-es/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Superior 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Usar modo Una mano"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para salir, desliza el dedo hacia arriba desde la parte inferior de la pantalla o toca cualquier zona que haya encima de la aplicación"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar modo Una mano"</string> diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml index 71f32cd32712..4722c074deb9 100644 --- a/libs/WindowManager/Shell/res/values-et/strings.xml +++ b/libs/WindowManager/Shell/res/values-et/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ülemine: 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Ülemine: 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Alumine täisekraan"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Ühekäerežiimi kasutamine"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Väljumiseks pühkige ekraani alaosast üles või puudutage rakenduse kohal olevat ala"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Ühekäerežiimi käivitamine"</string> diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml index a46095a35216..e1c2a0d25ee6 100644 --- a/libs/WindowManager/Shell/res/values-eu/strings.xml +++ b/libs/WindowManager/Shell/res/values-eu/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ezarri goialdea % 50en"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Ezarri goialdea % 30en"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ezarri behealdea pantaila osoan"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Esku bakarreko modua erabiltzea"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Irteteko, pasatu hatza pantailaren behealdetik gora edo sakatu aplikazioaren gainaldea"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Abiarazi esku bakarreko modua"</string> diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml index 214330ec309c..5a4871d7c6cc 100644 --- a/libs/WindowManager/Shell/res/values-fa/strings.xml +++ b/libs/WindowManager/Shell/res/values-fa/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"٪۵۰ بالا"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"٪۳۰ بالا"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"تمامصفحه پایین"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"استفاده از حالت یکدستی"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"برای خارج شدن، از پایین صفحهنمایش تند بهطرف بالا بکشید یا در هر جایی از بالای برنامه که میخواهید ضربه بزنید"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"آغاز «حالت یکدستی»"</string> diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml index b6972c644410..56f444e4e9a2 100644 --- a/libs/WindowManager/Shell/res/values-fi/strings.xml +++ b/libs/WindowManager/Shell/res/values-fi/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yläosa 50 %"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Yläosa 30 %"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Alaosa koko näytölle"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Yhden käden moodin käyttö"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Poistu pyyhkäisemällä ylös näytön alareunasta tai napauttamalla sovelluksen yllä"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Käynnistä yhden käden moodi"</string> diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml index 6ed74e4d2014..e48d794b3ac3 100644 --- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % dans le haut"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % dans le haut"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Plein écran dans le bas"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utiliser le mode Une main"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pour quitter, balayez l\'écran du bas vers le haut, ou touchez n\'importe où sur l\'écran en haut de l\'application"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Démarrer le mode Une main"</string> diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml index 82f02ce27220..301bca6434c3 100644 --- a/libs/WindowManager/Shell/res/values-fr/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Écran du haut à 50 %"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Écran du haut à 30 %"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Écran du bas en plein écran"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utiliser le mode une main"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pour quitter, balayez l\'écran de bas en haut ou appuyez n\'importe où au-dessus de l\'application"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Démarrer le mode une main"</string> diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml index b83be3daa205..967945ce64b8 100644 --- a/libs/WindowManager/Shell/res/values-gl/strings.xml +++ b/libs/WindowManager/Shell/res/values-gl/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % arriba"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % arriba"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla completa abaixo"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Como se usa o modo dunha soa man?"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para saír, pasa o dedo cara arriba desde a parte inferior da pantalla ou toca calquera lugar da zona situada encima da aplicación"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar modo dunha soa man"</string> diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml index d2e5a82bb0aa..653e1a69e698 100644 --- a/libs/WindowManager/Shell/res/values-gu/strings.xml +++ b/libs/WindowManager/Shell/res/values-gu/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"શીર્ષ 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"શીર્ષ 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"તળિયાની પૂર્ણ સ્ક્રીન"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"એક-હાથે વાપરો મોડનો ઉપયોગ કરી રહ્યાં છીએ"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"બહાર નીકળવા માટે, સ્ક્રીનની નીચેના ભાગથી ઉપરની તરફ સ્વાઇપ કરો અથવા ઍપના આઇકન પર ગમે ત્યાં ટૅપ કરો"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"એક-હાથે વાપરો મોડ શરૂ કરો"</string> diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml index ef4c2d96e5f5..25b658adf05f 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ऊपर की स्क्रीन को 50% बनाएं"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ऊपर की स्क्रीन को 30% बनाएं"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"नीचे की स्क्रीन को फ़ुल स्क्रीन बनाएं"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"वन-हैंडेड मोड का इस्तेमाल करना"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"इस मोड से बाहर निकलने के लिए, स्क्रीन के सबसे निचले हिस्से से ऊपर की ओर स्वाइप करें या ऐप्लिकेशन के बाहर कहीं भी टैप करें"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"वन-हैंडेड मोड चालू करें"</string> diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml index bbd95f7073ce..57fd2fa3c937 100644 --- a/libs/WindowManager/Shell/res/values-hr/strings.xml +++ b/libs/WindowManager/Shell/res/values-hr/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gornji zaslon na 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gornji zaslon na 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Donji zaslon u cijeli zaslon"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Korištenje načina rada jednom rukom"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Za izlaz prijeđite prstom od dna zaslona prema gore ili dodirnite bio gdje iznad aplikacije"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Pokretanje načina rada jednom rukom"</string> diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml index 1bb221344f4f..ee7ff866e79d 100644 --- a/libs/WindowManager/Shell/res/values-hu/strings.xml +++ b/libs/WindowManager/Shell/res/values-hu/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Felső 50%-ra"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Felső 30%-ra"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Alsó teljes képernyőre"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Egykezes mód használata"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"A kilépéshez csúsztasson felfelé a képernyő aljáról, vagy koppintson az alkalmazás felett a képernyő bármelyik részére"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Egykezes mód indítása"</string> diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml index 223ecf164e66..4538cec37ec1 100644 --- a/libs/WindowManager/Shell/res/values-hy/strings.xml +++ b/libs/WindowManager/Shell/res/values-hy/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Վերևի էկրանը՝ 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Վերևի էկրանը՝ 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ներքևի էկրանը՝ լիաէկրան"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Ինչպես օգտվել մեկ ձեռքի ռեժիմից"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Դուրս գալու համար մատը սահեցրեք էկրանի ներքևից վերև կամ հպեք հավելվածի վերևում որևէ տեղ։"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Գործարկել մեկ ձեռքի ռեժիմը"</string> diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml index 72dece47cce4..6880d53a0bd7 100644 --- a/libs/WindowManager/Shell/res/values-in/strings.xml +++ b/libs/WindowManager/Shell/res/values-in/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Atas 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Atas 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Layar penuh di bawah"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Menggunakan mode satu tangan"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Untuk keluar, geser layar dari bawah ke atas atau ketuk di mana saja di atas aplikasi"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Mulai mode satu tangan"</string> diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml index aaa48463420f..23c93a3faa43 100644 --- a/libs/WindowManager/Shell/res/values-is/strings.xml +++ b/libs/WindowManager/Shell/res/values-is/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Efri 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Efri 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Neðri á öllum skjánum"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Notkun einhentrar stillingar"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Til að loka skaltu strjúka upp frá neðri hluta skjásins eða ýta hvar sem er fyrir ofan forritið"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Ræsa einhenta stillingu"</string> diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml index 98d1b45c3a82..ece92cf9c922 100644 --- a/libs/WindowManager/Shell/res/values-it/strings.xml +++ b/libs/WindowManager/Shell/res/values-it/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Schermata superiore al 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Schermata superiore al 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Schermata inferiore a schermo intero"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Usare la modalità a una mano"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Per uscire, scorri verso l\'alto dalla parte inferiore dello schermo oppure tocca un punto qualsiasi sopra l\'app"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Avvia la modalità a una mano"</string> diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml index 9d7c2c0a9f88..948137f770f6 100644 --- a/libs/WindowManager/Shell/res/values-iw/strings.xml +++ b/libs/WindowManager/Shell/res/values-iw/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"עליון 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"למעלה 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"מסך תחתון מלא"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"איך להשתמש בתכונה \'מצב שימוש ביד אחת\'"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"כדי לצאת, יש להחליק למעלה מתחתית המסך או להקיש במקום כלשהו במסך מעל האפליקציה"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"הפעלה של מצב שימוש ביד אחת"</string> diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml index 548d63c50dc3..9fdb86100b2e 100644 --- a/libs/WindowManager/Shell/res/values-ja/strings.xml +++ b/libs/WindowManager/Shell/res/values-ja/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"上 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"上 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"下部全画面"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"片手モードの使用"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"終了するには、画面を下から上にスワイプするか、アプリの任意の場所をタップします"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"片手モードを開始します"</string> diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml index 1b359b39e63a..d827f1967458 100644 --- a/libs/WindowManager/Shell/res/values-ka/strings.xml +++ b/libs/WindowManager/Shell/res/values-ka/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ზედა ეკრანი — 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ზედა ეკრანი — 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ქვედა ნაწილის სრულ ეკრანზე გაშლა"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"ცალი ხელის რეჟიმის გამოყენება"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"გასასვლელად გადაფურცლეთ ეკრანის ქვედა კიდიდან ზემოთ ან შეეხეთ ნებისმიერ ადგილას აპის ზემოთ"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ცალი ხელის რეჟიმის დაწყება"</string> diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml index 2ce45e27be14..b0b03755c7ca 100644 --- a/libs/WindowManager/Shell/res/values-kk/strings.xml +++ b/libs/WindowManager/Shell/res/values-kk/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% жоғарғы жақта"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% жоғарғы жақта"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Төменгісін толық экранға шығару"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Бір қолмен енгізу режимін пайдалану"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Шығу үшін экранның төменгі жағынан жоғары қарай сырғытыңыз немесе қолданбаның үстінен кез келген жерден түртіңіз."</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Бір қолмен енгізу режимін іске қосу"</string> diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml index de872617d58e..3783067d1dd5 100644 --- a/libs/WindowManager/Shell/res/values-km/strings.xml +++ b/libs/WindowManager/Shell/res/values-km/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ខាងលើ 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ខាងលើ 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"អេក្រង់ពេញខាងក្រោម"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"កំពុងប្រើមុខងារប្រើដៃម្ខាង"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"ដើម្បីចាកចេញ សូមអូសឡើងលើពីផ្នែកខាងក្រោមអេក្រង់ ឬចុចផ្នែកណាមួយនៅខាងលើកម្មវិធី"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ចាប់ផ្ដើមមុខងារប្រើដៃម្ខាង"</string> diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml index 9b47a00dcb4c..45fd76fdaa44 100644 --- a/libs/WindowManager/Shell/res/values-kn/strings.xml +++ b/libs/WindowManager/Shell/res/values-kn/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% ಮೇಲಕ್ಕೆ"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% ಮೇಲಕ್ಕೆ"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ಕೆಳಗಿನ ಪೂರ್ಣ ಪರದೆ"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"ಒಂದು ಕೈ ಮೋಡ್ ಬಳಸುವುದರ ಬಗ್ಗೆ"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"ನಿರ್ಗಮಿಸಲು, ಸ್ಕ್ರೀನ್ನ ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಅಥವಾ ಆ್ಯಪ್ನ ಮೇಲೆ ಎಲ್ಲಿಯಾದರೂ ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ಒಂದು ಕೈ ಮೋಡ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಿ"</string> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index 6fa6386e47cf..0ee1feb979e5 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"위쪽 화면 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"위쪽 화면 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"아래쪽 화면 전체화면"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"한 손 사용 모드 사용하기"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"화면 하단에서 위로 스와이프하거나 앱 상단을 탭하여 종료합니다."</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"한 손 사용 모드 시작"</string> diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml index c2368d28d364..6798f498c579 100644 --- a/libs/WindowManager/Shell/res/values-ky/strings.xml +++ b/libs/WindowManager/Shell/res/values-ky/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Үстүнкү экранды 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Үстүнкү экранды 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ылдыйкы экранды толук экран режимине өткөрүү"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Бир кол режимин колдонуу"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Чыгуу үчүн экранды ылдый жагынан өйдө сүрүңүз же колдонмонун өйдө жагын басыңыз"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Бир кол режимин баштоо"</string> diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml index f4ff5e52cc60..b758c0cb7c8a 100644 --- a/libs/WindowManager/Shell/res/values-lo/strings.xml +++ b/libs/WindowManager/Shell/res/values-lo/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ເທິງສຸດ 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ເທິງສຸດ 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ເຕັມໜ້າຈໍລຸ່ມສຸດ"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"ກຳລັງໃຊ້ໂໝດມືດຽວ"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"ເພື່ອອອກ, ໃຫ້ປັດຂຶ້ນຈາກລຸ່ມສຸດຂອງໜ້າຈໍ ຫຼື ແຕະບ່ອນໃດກໍໄດ້ຢູ່ເໜືອແອັບ"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ເລີ່ມໂໝດມືດຽວ"</string> diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml index 0d276ecd37a1..84f42640b185 100644 --- a/libs/WindowManager/Shell/res/values-lt/strings.xml +++ b/libs/WindowManager/Shell/res/values-lt/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Viršutinis ekranas 50 %"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Viršutinis ekranas 30 %"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Apatinis ekranas viso ekrano režimu"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Vienos rankos režimo naudojimas"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Jei norite išeiti, perbraukite aukštyn nuo ekrano apačios arba palieskite bet kur virš programos"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Pradėti vienos rankos režimą"</string> diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml index c6ccc27a024b..bac75e3a5141 100644 --- a/libs/WindowManager/Shell/res/values-lv/strings.xml +++ b/libs/WindowManager/Shell/res/values-lv/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Augšdaļa 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Augšdaļa 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Apakšdaļu pa visu ekrānu"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Vienas rokas režīma izmantošana"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Lai izietu, velciet augšup no ekrāna apakšdaļas vai pieskarieties jebkurā vietā virs lietotnes"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Pāriet vienas rokas režīmā"</string> diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml index 526093df490f..b96f8a1a5e5c 100644 --- a/libs/WindowManager/Shell/res/values-mk/strings.xml +++ b/libs/WindowManager/Shell/res/values-mk/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горниот 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Горниот 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Долниот на цел екран"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Користење на режимот со една рака"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"За да излезете, повлечете нагоре од дното на екранот или допрете каде било над апликацијата"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Започни го режимот со една рака"</string> diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml index bd3d94ee4c21..f67e7abe5b63 100644 --- a/libs/WindowManager/Shell/res/values-ml/strings.xml +++ b/libs/WindowManager/Shell/res/values-ml/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"മുകളിൽ 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"മുകളിൽ 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"താഴെ പൂർണ്ണ സ്ക്രീൻ"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"ഒറ്റക്കൈ മോഡ് എങ്ങനെ ഉപയോഗിക്കാം"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"പുറത്ത് കടക്കാൻ, സ്ക്രീനിന്റെ ചുവടെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക അല്ലെങ്കിൽ ആപ്പിന് മുകളിലായി എവിടെയെങ്കിലും ടാപ്പ് ചെയ്യുക"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ഒറ്റക്കൈ മോഡ് ആരംഭിച്ചു"</string> diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml index bd1e31e4762e..00846ef749cd 100644 --- a/libs/WindowManager/Shell/res/values-mn/strings.xml +++ b/libs/WindowManager/Shell/res/values-mn/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Дээд 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Дээд 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Доод бүтэн дэлгэц"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Нэг гарын горимыг ашиглаж байна"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Гарахын тулд дэлгэцийн доод хэсгээс дээш шударч эсвэл апп дээр хүссэн газраа товшино уу"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Нэг гарын горимыг эхлүүлэх"</string> diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml index 01bf9494fe39..888e8ddcd0c9 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"शीर्ष 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"शीर्ष 10"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"तळाशी फुल स्क्रीन"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"एकहाती मोड वापरणे"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"बाहेर पडण्यासाठी स्क्रीनच्या खालून वरच्या दिशेने स्वाइप करा किंवा ॲपवर कोठेही टॅप करा"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"एकहाती मोड सुरू करा"</string> diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml index c9dc2ebe7049..d4a659ba9ae9 100644 --- a/libs/WindowManager/Shell/res/values-ms/strings.xml +++ b/libs/WindowManager/Shell/res/values-ms/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Atas 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Atas 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Skrin penuh bawah"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Menggunakan mod sebelah tangan"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Untuk keluar, leret ke atas daripada bahagian bawah skrin atau ketik pada mana-mana di bahagian atas apl"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Mulakan mod sebelah tangan"</string> diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml index 5f0a4124efa2..6f8b3c7c54a8 100644 --- a/libs/WindowManager/Shell/res/values-my/strings.xml +++ b/libs/WindowManager/Shell/res/values-my/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"အပေါ်ဘက် မျက်နှာပြင် ၅၀%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"အပေါ်ဘက် မျက်နှာပြင် ၃၀%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"အောက်ခြေ မျက်နှာပြင်အပြည့်"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"လက်တစ်ဖက်သုံးမုဒ် အသုံးပြုခြင်း"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"ထွက်ရန် ဖန်သားပြင်၏အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ သို့မဟုတ် အက်ပ်အပေါ်ဘက် မည်သည့်နေရာတွင်မဆို တို့ပါ"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"လက်တစ်ဖက်သုံးမုဒ်ကို စတင်လိုက်သည်"</string> diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml index e84c95d36b96..1ea390757b6c 100644 --- a/libs/WindowManager/Shell/res/values-nb/strings.xml +++ b/libs/WindowManager/Shell/res/values-nb/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Sett størrelsen på den øverste delen av skjermen til 50 %"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Sett størrelsen på den øverste delen av skjermen til 30 %"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Utvid den nederste delen av skjermen til hele skjermen"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Bruk av enhåndsmodus"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"For å avslutte, sveip opp fra bunnen av skjermen eller trykk hvor som helst over appen"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Start enhåndsmodus"</string> diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index f1997bee71da..fd3485c8396a 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"माथिल्लो भाग ५०%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"माथिल्लो भाग ३०%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"तल्लो भाग फुल स्क्रिन"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"एक हाते मोड प्रयोग गरिँदै छ"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"बाहिर निस्कन, स्क्रिनको पुछारबाट माथितिर स्वाइप गर्नुहोस् वा एपभन्दा माथि जुनसुकै ठाउँमा ट्याप गर्नुहोस्"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"एक हाते मोड सुरु गर्नुहोस्"</string> diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml index ba37ca745ea6..c3ab297c899d 100644 --- a/libs/WindowManager/Shell/res/values-nl/strings.xml +++ b/libs/WindowManager/Shell/res/values-nl/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bovenste scherm 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Bovenste scherm 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Onderste scherm op volledig scherm"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Bediening met 1 hand gebruiken"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Als je wilt afsluiten, swipe je omhoog vanaf de onderkant van het scherm of tik je ergens boven de app"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Bediening met 1 hand starten"</string> diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml index 7ae576a9d374..90c90d316c78 100644 --- a/libs/WindowManager/Shell/res/values-or/strings.xml +++ b/libs/WindowManager/Shell/res/values-or/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ଉପର ଆଡ଼କୁ 50% କରନ୍ତୁ"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ଉପର ଆଡ଼କୁ 30% କରନ୍ତୁ"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ତଳ ଅଂଶର ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"ଏକ-ହାତ ମୋଡ୍ ବ୍ୟବହାର କରି"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"ବାହାରି ଯିବା ପାଇଁ, ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ କିମ୍ବା ଆପରେ ଯେ କୌଣସି ସ୍ଥାନରେ ଟାପ୍ କରନ୍ତୁ"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ଏକ-ହାତ ମୋଡ୍ ଆରମ୍ଭ କରନ୍ତୁ"</string> diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml index 6784354e7103..b27e034fd655 100644 --- a/libs/WindowManager/Shell/res/values-pa/strings.xml +++ b/libs/WindowManager/Shell/res/values-pa/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ਉੱਪਰ 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ਉੱਪਰ 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ਹੇਠਾਂ ਪੂਰੀ ਸਕ੍ਰੀਨ"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"ਇੱਕ ਹੱਥ ਮੋਡ ਵਰਤਣਾ"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"ਬਾਹਰ ਜਾਣ ਲਈ, ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ ਜਾਂ ਐਪ \'ਤੇ ਕਿਤੇ ਵੀ ਟੈਪ ਕਰੋ"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ਇੱਕ ਹੱਥ ਮੋਡ ਸ਼ੁਰੂ ਕਰੋ"</string> diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml index 962ba0ddae20..6d00aaa1f17e 100644 --- a/libs/WindowManager/Shell/res/values-pl/strings.xml +++ b/libs/WindowManager/Shell/res/values-pl/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% górnej części ekranu"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% górnej części ekranu"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Dolna część ekranu na pełnym ekranie"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Korzystanie z trybu jednej ręki"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Aby zamknąć, przesuń palcem z dołu ekranu w górę lub kliknij dowolne miejsce nad aplikacją"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Uruchom tryb jednej ręki"</string> diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml index a94d157f48aa..b2f3121fd98b 100644 --- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Parte superior a 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Parte superior a 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Parte inferior em tela cheia"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Como usar o modo para uma mão"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para sair, deslize de baixo para cima na tela ou toque em qualquer lugar acima do app"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar o modo para uma mão"</string> diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml index 345a89ee499b..3f3be4bc8943 100644 --- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% no ecrã superior"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% no ecrã superior"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ecrã inferior inteiro"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Utilize o modo para uma mão"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para sair, deslize rapidamente para cima a partir da parte inferior do ecrã ou toque em qualquer ponto acima da app."</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar o modo para uma mão"</string> diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml index a94d157f48aa..b2f3121fd98b 100644 --- a/libs/WindowManager/Shell/res/values-pt/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Parte superior a 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Parte superior a 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Parte inferior em tela cheia"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Como usar o modo para uma mão"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para sair, deslize de baixo para cima na tela ou toque em qualquer lugar acima do app"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Iniciar o modo para uma mão"</string> diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml index fa9a07454b4f..402ef6b1834c 100644 --- a/libs/WindowManager/Shell/res/values-ro/strings.xml +++ b/libs/WindowManager/Shell/res/values-ro/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Partea de sus: 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Partea de sus: 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Partea de jos pe ecran complet"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Folosirea modului cu o mână"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pentru a ieși, glisează în sus din partea de jos a ecranului sau atinge oriunde deasupra ferestrei aplicației"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Activează modul cu o mână"</string> diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml index b9c59514b939..dd595455963b 100644 --- a/libs/WindowManager/Shell/res/values-ru/strings.xml +++ b/libs/WindowManager/Shell/res/values-ru/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхний на 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Верхний на 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Нижний во весь экран"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Использование режима управления одной рукой"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Чтобы выйти, проведите по экрану снизу вверх или коснитесь области за пределами приложения."</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Запустить режим управления одной рукой"</string> diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml index c2d7c1ae6a64..91342c483a5d 100644 --- a/libs/WindowManager/Shell/res/values-si/strings.xml +++ b/libs/WindowManager/Shell/res/values-si/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ඉහළම 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ඉහළම 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"පහළ පූර්ණ තිරය"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"තනි-අත් ප්රකාරය භාවිත කරමින්"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"පිටවීමට, තිරයේ පහළ සිට ඉහළට ස්වයිප් කරන්න හෝ යෙදුමට ඉහළින් ඕනෑම තැනක තට්ටු කරන්න"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"තනි අත් ප්රකාරය ආරම්භ කරන්න"</string> diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml index 7bb415dc474c..b9199c2631fd 100644 --- a/libs/WindowManager/Shell/res/values-sk/strings.xml +++ b/libs/WindowManager/Shell/res/values-sk/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Horná – 50 %"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Horná – 30 %"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Dolná – na celú obrazovku"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Používanie režimu jednej ruky"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Ukončíte potiahnutím z dolnej časti obrazovky nahor alebo klepnutím kdekoľvek nad aplikáciu"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Spustiť režim jednej ruky"</string> diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml index a64c52fa8778..0fd44f086029 100644 --- a/libs/WindowManager/Shell/res/values-sl/strings.xml +++ b/libs/WindowManager/Shell/res/values-sl/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Zgornji 50 %"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Zgornji 30 %"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Spodnji v celozaslonski način"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Uporaba enoročnega načina"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Za izhod povlecite z dna zaslona navzgor ali se dotaknite na poljubnem mestu nad aplikacijo"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Zagon enoročnega načina"</string> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index f4fc5e75d6a4..00e63d2e5027 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Lart 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Lart 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ekrani i plotë poshtë"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Po përdor modalitetin e përdorimit me një dorë"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Për të dalë, rrëshqit lart nga fundi i ekranit ose trokit diku mbi aplikacion"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Modaliteti i përdorimit me një dorë"</string> diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml index 743f9a84a89e..d0f689c3236d 100644 --- a/libs/WindowManager/Shell/res/values-sr/strings.xml +++ b/libs/WindowManager/Shell/res/values-sr/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горњи екран 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Горњи екран 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Режим целог екрана за доњи екран"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Коришћење режима једном руком"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Да бисте изашли, превуците нагоре од дна екрана или додирните било где изнад апликације"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Покрените режим једном руком"</string> diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml index 6562f9de4c03..e3827d6b8278 100644 --- a/libs/WindowManager/Shell/res/values-sv/strings.xml +++ b/libs/WindowManager/Shell/res/values-sv/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Övre 50 %"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Övre 30 %"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Helskärm på nedre skärm"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Använda enhandsläge"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Avsluta genom att svepa uppåt från skärmens nederkant eller trycka ovanför appen"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Starta enhandsläge"</string> diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml index 56a1a32d02e8..8c2f2ad9e6fe 100644 --- a/libs/WindowManager/Shell/res/values-sw/strings.xml +++ b/libs/WindowManager/Shell/res/values-sw/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Juu 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Juu 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Skrini nzima ya chini"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Kutumia hali ya kutumia kwa mkono mmoja"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Ili ufunge, telezesha kidole juu kutoka sehemu ya chini ya skrini au uguse mahali popote juu ya programu"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Anzisha hali ya kutumia kwa mkono mmoja"</string> diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml index 2f5426452cad..4732e391cd56 100644 --- a/libs/WindowManager/Shell/res/values-ta/strings.xml +++ b/libs/WindowManager/Shell/res/values-ta/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"மேலே 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"மேலே 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"கீழ்ப்புறம் முழுத் திரை"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"ஒற்றைக் கைப் பயன்முறையைப் பயன்படுத்துதல்"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"வெளியேற, திரையின் கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்யவும் அல்லது ஆப்ஸுக்கு மேலே ஏதேனும் ஓர் இடத்தில் தட்டவும்"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ஒற்றைக் கைப் பயன்முறையைத் தொடங்கும்"</string> diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml index 6e4986592bf4..093a8487b3e4 100644 --- a/libs/WindowManager/Shell/res/values-te/strings.xml +++ b/libs/WindowManager/Shell/res/values-te/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ఎగువ 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ఎగువ 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"దిగువ ఫుల్-స్క్రీన్"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"వన్-హ్యాండెడ్ మోడ్ను ఉపయోగించడం"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"నిష్క్రమించడానికి, స్క్రీన్ కింది భాగం నుండి పైకి స్వైప్ చేయండి లేదా యాప్ పైన ఎక్కడైనా ట్యాప్ చేయండి"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"వన్-హ్యాండెడ్ మోడ్ను ప్రారంభిస్తుంది"</string> diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml index a9100e8a9453..f7c810b02561 100644 --- a/libs/WindowManager/Shell/res/values-th/strings.xml +++ b/libs/WindowManager/Shell/res/values-th/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ด้านบน 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ด้านบน 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"เต็มหน้าจอด้านล่าง"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"การใช้โหมดมือเดียว"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"หากต้องการออก ให้เลื่อนขึ้นจากด้านล่างของหน้าจอหรือแตะที่ใดก็ได้เหนือแอป"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"เริ่มโหมดมือเดียว"</string> diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml index 7a4232cc15d6..4660d6d0c9ee 100644 --- a/libs/WindowManager/Shell/res/values-tl/strings.xml +++ b/libs/WindowManager/Shell/res/values-tl/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gawing 50% ang nasa itaas"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gawing 30% ang nasa itaas"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"I-full screen ang nasa ibaba"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Paggamit ng one-hand mode"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Para lumabas, mag-swipe pataas mula sa ibaba ng screen o mag-tap kahit saan sa itaas ng app"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Simulan ang one-hand mode"</string> diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml index 55e36dd3b291..6fdfe56c2b36 100644 --- a/libs/WindowManager/Shell/res/values-tr/strings.xml +++ b/libs/WindowManager/Shell/res/values-tr/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Üstte %50"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Üstte %30"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Altta tam ekran"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Tek el modunu kullanma"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Çıkmak için ekranın alt kısmından yukarı kaydırın veya uygulamanın üzerinde herhangi bir yere dokunun"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Tek el modunu başlat"</string> diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml index 2b04b907c264..c5cfd02eec6c 100644 --- a/libs/WindowManager/Shell/res/values-uk/strings.xml +++ b/libs/WindowManager/Shell/res/values-uk/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхнє вікно на 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Верхнє вікно на 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Нижнє вікно на весь екран"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Як користуватися режимом керування однією рукою"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Щоб вийти, проведіть пальцем по екрану знизу вгору або торкніться екрана над додатком"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Увімкнути режим керування однією рукою"</string> diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml index 8f818cb71d03..9c138d9164b9 100644 --- a/libs/WindowManager/Shell/res/values-ur/strings.xml +++ b/libs/WindowManager/Shell/res/values-ur/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"اوپر %50"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"اوپر %30"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"نچلی فل اسکرین"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"ایک ہاتھ کی وضع کا استعمال کرنا"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"باہر نکلنے کیلئے، اسکرین کے نیچے سے اوپر کی طرف سوائپ کریں یا ایپ کے اوپر کہیں بھی تھپتھپائیں"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"ایک ہاتھ کی وضع شروع کریں"</string> diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml index a666cd90b2e3..907c5bdc2753 100644 --- a/libs/WindowManager/Shell/res/values-uz/strings.xml +++ b/libs/WindowManager/Shell/res/values-uz/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Tepada 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Tepada 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pastda to‘liq ekran"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Ixcham rejimdan foydalanish"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Chiqish uchun ekran pastidan tepaga suring yoki ilovaning tepasidagi istalgan joyga bosing."</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Ixcham rejimni ishga tushirish"</string> diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml index a78e01cc887e..211e231943b4 100644 --- a/libs/WindowManager/Shell/res/values-vi/strings.xml +++ b/libs/WindowManager/Shell/res/values-vi/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Trên 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Trên 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Toàn màn hình phía dưới"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Cách dùng chế độ một tay"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Để thoát, hãy vuốt lên từ cuối màn hình hoặc nhấn vào vị trí bất kỳ phía trên ứng dụng"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Bắt đầu chế độ một tay"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index bb3cf396c2af..3d0637a37173 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"顶部 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"顶部 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"底部全屏"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"使用单手模式"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"如需退出,请从屏幕底部向上滑动,或点按应用上方的任意位置"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"启动单手模式"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml index 724f0120d7b8..c4df0864004d 100644 --- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"頂部 50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"頂部 30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"底部全螢幕"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"使用單手模式"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"如要退出,請從螢幕底部向上滑動,或輕按應用程式上方的任何位置"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"開始單手模式"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml index 082049f7d2f9..2d9e7f3a4f43 100644 --- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"以 50% 的螢幕空間顯示頂端畫面"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"以 30% 的螢幕空間顯示頂端畫面"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"以全螢幕顯示底部畫面"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"使用單手模式"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"如要退出,請從螢幕底部向上滑動,或輕觸應用程式上方的任何位置"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"啟動單手模式"</string> diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml index 18f722c9f7a1..5c600560dca4 100644 --- a/libs/WindowManager/Shell/res/values-zu/strings.xml +++ b/libs/WindowManager/Shell/res/values-zu/strings.xml @@ -47,6 +47,14 @@ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Okuphezulu okungu-50%"</string> <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Okuphezulu okungu-30%"</string> <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ngaphansi kwesikrini esigcwele"</string> + <!-- no translation found for accessibility_split_left (1713683765575562458) --> + <skip /> + <!-- no translation found for accessibility_split_right (8441001008181296837) --> + <skip /> + <!-- no translation found for accessibility_split_top (2789329702027147146) --> + <skip /> + <!-- no translation found for accessibility_split_bottom (8694551025220868191) --> + <skip /> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Ukusebenzisa imodi yesandla esisodwa"</string> <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Ukuze uphume, swayipha ngaphezulu kusuka ngezansi kwesikrini noma thepha noma kuphi ngenhla kohlelo lokusebenza"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Qalisa imodi yesandla esisodwa"</string> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 8908959b89fa..6f31d0674246 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -228,7 +228,7 @@ <dimen name="bubble_user_education_stack_padding">16dp</dimen> <!-- Bottom and end margin for compat buttons. --> - <dimen name="compat_button_margin">16dp</dimen> + <dimen name="compat_button_margin">24dp</dimen> <!-- The radius of the corners of the compat hint bubble. --> <dimen name="compat_hint_corner_radius">28dp</dimen> @@ -367,8 +367,12 @@ <!-- Width of buttons (32dp each) + padding (128dp total). --> <dimen name="freeform_decor_caption_menu_width">256dp</dimen> + <dimen name="freeform_decor_caption_menu_height">250dp</dimen> + <dimen name="freeform_resize_handle">30dp</dimen> <dimen name="freeform_resize_corner">44dp</dimen> + <dimen name="caption_menu_elevation">4dp</dimen> + </resources> diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml index adc65dd7f699..6399232919d2 100644 --- a/libs/WindowManager/Shell/res/values/strings.xml +++ b/libs/WindowManager/Shell/res/values/strings.xml @@ -225,6 +225,8 @@ <string name="back_button_text">Back</string> <!-- Accessibility text for the caption handle [CHAR LIMIT=NONE] --> <string name="handle_text">Handle</string> + <!-- Accessibility text for the handle menu app icon [CHAR LIMIT=NONE] --> + <string name="app_icon_text">App Icon</string> <!-- Accessibility text for the handle fullscreen button [CHAR LIMIT=NONE] --> <string name="fullscreen_text">Fullscreen</string> <!-- Accessibility text for the handle desktop button [CHAR LIMIT=NONE] --> @@ -235,4 +237,12 @@ <string name="more_button_text">More</string> <!-- Accessibility text for the handle floating window button [CHAR LIMIT=NONE] --> <string name="float_button_text">Float</string> + <!-- Accessibility text for the handle menu select button [CHAR LIMIT=NONE] --> + <string name="select_text">Select</string> + <!-- Accessibility text for the handle menu screenshot button [CHAR LIMIT=NONE] --> + <string name="screenshot_text">Screenshot</string> + <!-- Accessibility text for the handle menu close button [CHAR LIMIT=NONE] --> + <string name="close_text">Close</string> + <!-- Accessibility text for the handle menu close menu button [CHAR LIMIT=NONE] --> + <string name="collapse_menu_text">Close Menu</string> </resources> diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml index e8f340cdd066..bae009a0526f 100644 --- a/libs/WindowManager/Shell/res/values/styles.xml +++ b/libs/WindowManager/Shell/res/values/styles.xml @@ -37,6 +37,22 @@ <item name="android:padding">4dp</item> </style> + <style name="CaptionWindowingButtonStyle"> + <item name="android:layout_width">32dp</item> + <item name="android:layout_height">32dp</item> + <item name="android:padding">4dp</item> + <item name="android:layout_marginTop">5dp</item> + <item name="android:layout_marginBottom">5dp</item> + </style> + + <style name="CaptionMenuButtonStyle" parent="@style/Widget.AppCompat.Button.Borderless"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">52dp</item> + <item name="android:layout_marginStart">10dp</item> + <item name="android:padding">4dp</item> + <item name="android:gravity">start|center_vertical</item> + </style> + <style name="DockedDividerBackground"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">@dimen/split_divider_bar_width</item> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java index 9e0a48b13413..e2106e478bb3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java @@ -216,7 +216,6 @@ public class TaskStackListenerImpl extends TaskStackListener implements Handler. args.argi1 = homeTaskVisible ? 1 : 0; args.argi2 = clearedTask ? 1 : 0; args.argi3 = wasVisible ? 1 : 0; - mMainHandler.removeMessages(ON_ACTIVITY_RESTART_ATTEMPT); mMainHandler.obtainMessage(ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget(); } 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 index d85041642c3a..bc8171058776 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java @@ -22,6 +22,7 @@ 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 android.view.WindowManager.TRANSIT_CHANGE; +import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; @@ -256,10 +257,13 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll WindowContainerTransaction wct = new WindowContainerTransaction(); bringDesktopAppsToFront(wct); - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - mTransitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */); - } else { - mShellTaskOrganizer.applyTransaction(wct); + if (!wct.isEmpty()) { + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + // TODO(b/268662477): add animation for the transition + mTransitions.startTransition(TRANSIT_NONE, wct, null /* handler */); + } else { + mShellTaskOrganizer.applyTransaction(wct); + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 23033253eaf9..fce013837f01 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -27,6 +27,7 @@ import android.content.Context import android.os.IBinder import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE +import android.view.WindowManager.TRANSIT_NONE import android.view.WindowManager.TRANSIT_OPEN import android.view.WindowManager.TRANSIT_TO_FRONT import android.window.TransitionInfo @@ -89,7 +90,8 @@ class DesktopTasksController( // Execute transaction if there are pending operations if (!wct.isEmpty) { if (Transitions.ENABLE_SHELL_TRANSITIONS) { - transitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */) + // TODO(b/268662477): add animation for the transition + transitions.startTransition(TRANSIT_NONE, wct, null /* handler */) } else { shellTaskOrganizer.applyTransaction(wct) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index ffb2893e8ffa..f11836ea5bee 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -650,7 +650,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo); - mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER); // If the displayId of the task is different than what PipBoundsHandler has, then update // it. This is possible if we entered PiP on an external display. @@ -659,6 +658,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mOnDisplayIdChangeCallback.accept(info.displayId); } + // UiEvent logging. + final PipUiEventLogger.PipUiEventEnum uiEventEnum; + if (isLaunchIntoPipTask()) { + uiEventEnum = PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER_CONTENT_PIP; + } else if (mPipTransitionState.getInSwipePipToHomeTransition()) { + uiEventEnum = PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_AUTO_ENTER; + } else { + uiEventEnum = PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER; + } + mPipUiEventLoggerLogger.log(uiEventEnum); + if (mPipTransitionState.getInSwipePipToHomeTransition()) { if (!mWaitForFixedRotation) { onEndOfSwipePipToHomeTransition(); @@ -1409,7 +1419,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @PipAnimationController.TransitionDirection int direction, @PipAnimationController.AnimationType int type) { final Rect preResizeBounds = new Rect(mPipBoundsState.getBounds()); - final boolean isPipTopLeft = isPipTopLeft(); mPipBoundsState.setBounds(destinationBounds); if (direction == TRANSITION_DIRECTION_REMOVE_STACK) { removePipImmediately(); @@ -1455,9 +1464,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, null /* callback */, false /* withStartDelay */); }); } else { - applyFinishBoundsResize(wct, direction, isPipTopLeft); + applyFinishBoundsResize(wct, direction, false); } } else { + final boolean isPipTopLeft = + direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && isPipToTopLeft(); applyFinishBoundsResize(wct, direction, isPipTopLeft); } @@ -1526,6 +1537,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, return topLeft.contains(mPipBoundsState.getBounds()); } + private boolean isPipToTopLeft() { + if (!mSplitScreenOptional.isPresent()) { + return false; + } + return mSplitScreenOptional.get().getActivateSplitPosition(mTaskInfo) + == SPLIT_POSITION_TOP_OR_LEFT; + } + /** * The windowing mode to restore to when resizing out of PIP direction. Defaults to undefined * and can be overridden to restore to an alternate windowing mode. @@ -1662,8 +1681,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final Rect topLeft = new Rect(); final Rect bottomRight = new Rect(); mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight); - final boolean isPipTopLeft = isPipTopLeft(); - destinationBoundsOut.set(isPipTopLeft ? topLeft : bottomRight); + destinationBoundsOut.set(isPipToTopLeft() ? topLeft : bottomRight); return true; } @@ -1747,6 +1765,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceControlTransactionFactory = factory; } + public boolean isLaunchToSplit(TaskInfo taskInfo) { + return mSplitScreenOptional.isPresent() + && mSplitScreenOptional.get().isLaunchToSplit(taskInfo); + } + /** * Dumps internal states. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java index 513ebba59258..3e5a19b69a59 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java @@ -78,6 +78,12 @@ public class PipUiEventLogger { @UiEvent(doc = "Activity enters picture-in-picture mode") PICTURE_IN_PICTURE_ENTER(603), + @UiEvent(doc = "Activity enters picture-in-picture mode with auto-enter-pip API") + PICTURE_IN_PICTURE_AUTO_ENTER(1313), + + @UiEvent(doc = "Activity enters picture-in-picture mode from content-pip API") + PICTURE_IN_PICTURE_ENTER_CONTENT_PIP(1314), + @UiEvent(doc = "Expands from picture-in-picture to fullscreen") PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN(604), 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 4958b2557d09..ec34f73126fb 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 @@ -570,8 +570,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb if (task.getWindowingMode() != WINDOWING_MODE_PINNED) { return; } - mTouchHandler.getMotionHelper().expandLeavePip( - clearedTask /* skipAnimation */); + if (mPipTaskOrganizer.isLaunchToSplit(task)) { + mTouchHandler.getMotionHelper().expandIntoSplit(); + } else { + mTouchHandler.getMotionHelper().expandLeavePip( + clearedTask /* skipAnimation */); + } } }); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 36da4cf12706..c7ad4fdcacf0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -42,6 +42,7 @@ import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.PendingIntent; +import android.app.TaskInfo; import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; @@ -421,6 +422,14 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mStageCoordinator.goToFullscreenFromSplit(); } + public boolean isLaunchToSplit(TaskInfo taskInfo) { + return mStageCoordinator.isLaunchToSplit(taskInfo); + } + + public int getActivateSplitPosition(TaskInfo taskInfo) { + return mStageCoordinator.getActivateSplitPosition(taskInfo); + } + public void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options) { final int[] result = new int[1]; IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() { 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 0f18ddaba218..a42820d2e765 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 @@ -74,6 +74,7 @@ import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.IActivityTaskManager; import android.app.PendingIntent; +import android.app.TaskInfo; import android.app.WindowConfiguration; import android.content.ActivityNotFoundException; import android.content.Context; @@ -124,6 +125,7 @@ import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; +import com.android.wm.shell.common.split.SplitScreenUtils; import com.android.wm.shell.common.split.SplitWindowManager; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.recents.RecentTasksController; @@ -208,6 +210,36 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private DefaultMixedHandler mMixedHandler; private final Toast mSplitUnsupportedToast; + private SplitRequest mSplitRequest; + + class SplitRequest { + @SplitPosition + int mActivatePosition; + int mActivateTaskId; + int mActivateTaskId2; + Intent mStartIntent; + Intent mStartIntent2; + + SplitRequest(int taskId, Intent startIntent, int position) { + mActivateTaskId = taskId; + mStartIntent = startIntent; + mActivatePosition = position; + } + SplitRequest(Intent startIntent, int position) { + mStartIntent = startIntent; + mActivatePosition = position; + } + SplitRequest(Intent startIntent, Intent startIntent2, int position) { + mStartIntent = startIntent; + mStartIntent2 = startIntent2; + mActivatePosition = position; + } + SplitRequest(int taskId1, int taskId2, int position) { + mActivateTaskId = taskId1; + mActivateTaskId2 = taskId2; + mActivatePosition = position; + } + } private final SplitWindowManager.ParentContainerCallbacks mParentContainerCallbacks = new SplitWindowManager.ParentContainerCallbacks() { @@ -393,6 +425,23 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, setSideStagePosition(sideStagePosition, wct); final WindowContainerTransaction evictWct = new WindowContainerTransaction(); targetStage.evictAllChildren(evictWct); + + // Apply surface bounds before animation start. + SurfaceControl.Transaction startT = mTransactionPool.acquire(); + if (startT != null) { + updateSurfaceBounds(mSplitLayout, startT, false /* applyResizingOffset */); + startT.apply(); + mTransactionPool.release(startT); + } + // reparent the task to an invisible split root will make the activity invisible. Reorder + // the root task to front to make the entering transition from pip to split smooth. + wct.reorder(mRootTaskInfo.token, true); + wct.setForceTranslucent(mRootTaskInfo.token, true); + wct.reorder(targetStage.mRootTaskInfo.token, true); + wct.setForceTranslucent(targetStage.mRootTaskInfo.token, true); + // prevent the fling divider to center transition + mIsDropEntering = true; + targetStage.addTask(task, wct); if (ENABLE_SHELL_TRANSITIONS) { @@ -547,7 +596,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } - if (isEnteringSplit && !openingToSide) { + if (isEnteringSplit && !openingToSide && apps != null) { mMainExecutor.execute(() -> exitSplitScreen( mSideStage.getChildCount() == 0 ? mMainStage : mSideStage, EXIT_REASON_UNKNOWN)); @@ -587,7 +636,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (isEnteringSplit && mLogger.isEnterRequestedByDrag()) { updateWindowBounds(mSplitLayout, wct); } - + mSplitRequest = new SplitRequest(intent.getIntent(), position); wct.sendPendingIntent(intent, fillInIntent, options); mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct); } @@ -686,6 +735,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, addActivityOptions(options1, mSideStage); wct.startTask(taskId1, options1); + mSplitRequest = new SplitRequest(taskId1, taskId2, splitPosition); startWithLegacyTransition(wct, taskId2, options2, splitPosition, splitRatio, adapter, instanceId); } @@ -719,6 +769,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, wct.startShortcut(mContext.getPackageName(), shortcutInfo1, options1); } else { wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1); + mSplitRequest = new SplitRequest(pendingIntent1.getIntent(), + pendingIntent2 != null ? pendingIntent2.getIntent() : null, splitPosition); } startWithLegacyTransition(wct, pendingIntent2, fillInIntent2, shortcutInfo2, options2, splitPosition, splitRatio, adapter, instanceId); @@ -743,6 +795,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, addActivityOptions(options1, mSideStage); wct.sendPendingIntent(pendingIntent, fillInIntent, options1); + mSplitRequest = new SplitRequest(taskId, pendingIntent.getIntent(), splitPosition); startWithLegacyTransition(wct, taskId, options2, splitPosition, splitRatio, adapter, instanceId); } @@ -815,7 +868,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Set false to avoid record new bounds with old task still on top; mShouldUpdateRecents = false; mIsSplitEntering = true; - + if (mSplitRequest == null) { + mSplitRequest = new SplitRequest(mainTaskId, + mainPendingIntent != null ? mainPendingIntent.getIntent() : null, + sidePosition); + } setSideStagePosition(sidePosition, wct); if (!mMainStage.isActive()) { mMainStage.activate(wct, false /* reparent */); @@ -906,6 +963,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, WindowContainerTransaction evictWct) { mIsSplitEntering = false; mShouldUpdateRecents = true; + mSplitRequest = null; // If any stage has no child after animation finished, it means that split will display // nothing, such status will happen if task and intent is same app but not support // multi-instance, we should exit split and expand that app as full screen. @@ -1739,7 +1797,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout.init(); final WindowContainerTransaction wct = new WindowContainerTransaction(); - if (mLogger.isEnterRequestedByDrag()) { + if (mIsDropEntering) { prepareEnterSplitScreen(wct); } else { // TODO (b/238697912) : Add the validation to prevent entering non-recovered status @@ -1764,6 +1822,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) { mShouldUpdateRecents = true; + mSplitRequest = null; updateRecentTasksSplitPair(); if (!mLogger.hasStartedSession()) { @@ -2316,6 +2375,33 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout.flingDividerToDismiss(!leftOrTop, EXIT_REASON_FULLSCREEN_SHORTCUT); } + boolean isLaunchToSplit(TaskInfo taskInfo) { + return getActivateSplitPosition(taskInfo) != SPLIT_POSITION_UNDEFINED; + } + + int getActivateSplitPosition(TaskInfo taskInfo) { + if (mSplitRequest == null || taskInfo == null) { + return SPLIT_POSITION_UNDEFINED; + } + if (mSplitRequest.mActivateTaskId != 0 + && mSplitRequest.mActivateTaskId2 == taskInfo.taskId) { + return mSplitRequest.mActivatePosition; + } + if (mSplitRequest.mActivateTaskId == taskInfo.taskId) { + return mSplitRequest.mActivatePosition; + } + final String packageName1 = SplitScreenUtils.getPackageName(mSplitRequest.mStartIntent); + final String basePackageName = SplitScreenUtils.getPackageName(taskInfo.baseIntent); + if (packageName1 != null && packageName1.equals(basePackageName)) { + return mSplitRequest.mActivatePosition; + } + final String packageName2 = SplitScreenUtils.getPackageName(mSplitRequest.mStartIntent2); + if (packageName2 != null && packageName2.equals(basePackageName)) { + return mSplitRequest.mActivatePosition; + } + return SPLIT_POSITION_UNDEFINED; + } + /** Synchronize split-screen state with transition and make appropriate preparations. */ public void prepareDismissAnimation(@StageType int toStage, @ExitReason int dismissReason, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index db6cbdc5176d..44e4a31c36f0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -156,6 +156,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } decoration.relayout(taskInfo); + setupCaptionColor(taskInfo, decoration); } @Override @@ -227,7 +228,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { public void onClick(View v) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); final int id = v.getId(); - if (id == R.id.caption_handle) { + if (id == R.id.close_window || id == R.id.close_button) { + mTaskOperations.closeTask(mTaskToken); + } else if (id == R.id.back_button) { + mTaskOperations.injectBackKey(); + } else if (id == R.id.caption_handle) { decoration.createHandleMenu(); } else if (id == R.id.desktop_button) { mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true)); @@ -238,6 +243,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mDesktopTasksController.ifPresent(c -> c.moveToFullscreen(mTaskId)); decoration.closeHandleMenu(); decoration.setButtonVisibility(false); + } else if (id == R.id.collapse_menu_button) { + decoration.closeHandleMenu(); } } @@ -508,6 +515,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } } + private void setupCaptionColor(RunningTaskInfo taskInfo, + DesktopModeWindowDecoration decoration) { + if (taskInfo == null || taskInfo.taskDescription == null) return; + final int statusBarColor = taskInfo.taskDescription.getStatusBarColor(); + decoration.setCaptionColor(statusBarColor); + } + private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) { if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true; return DesktopModeStatus.isProto2Enabled() @@ -546,6 +560,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { windowDecoration.setDragPositioningCallback(taskPositioner); windowDecoration.setDragDetector(touchEventListener.mDragDetector); windowDecoration.relayout(taskInfo, startT, finishT); + setupCaptionColor(taskInfo, windowDecoration); incrementEventReceiverTasks(taskInfo.displayId); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 744c18fe7adb..245cc8d7ee87 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -20,18 +20,25 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import android.app.ActivityManager; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Point; import android.graphics.PointF; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.VectorDrawable; import android.os.Handler; +import android.util.Log; import android.view.Choreographer; import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.View; import android.view.ViewConfiguration; +import android.widget.ImageView; +import android.widget.TextView; import android.window.WindowContainerTransaction; import com.android.wm.shell.R; @@ -48,6 +55,7 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus; * The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't. */ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLinearLayout> { + private static final String TAG = "DesktopModeWindowDecoration"; private final Handler mHandler; private final Choreographer mChoreographer; private final SyncTransactionQueue mSyncQueue; @@ -59,12 +67,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private DragDetector mDragDetector; private RelayoutParams mRelayoutParams = new RelayoutParams(); - private final int mCaptionMenuWidthId = R.dimen.freeform_decor_caption_menu_width; + private final int mCaptionMenuHeightId = R.dimen.freeform_decor_caption_menu_height; private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult = new WindowDecoration.RelayoutResult<>(); private boolean mDesktopActive; private AdditionalWindow mHandleMenu; + private final int mHandleMenuWidthId = R.dimen.freeform_decor_caption_menu_width; + private PointF mHandleMenuPosition = new PointF(); DesktopModeWindowDecoration( Context context, @@ -211,21 +221,46 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final View fullscreen = menu.findViewById(R.id.fullscreen_button); fullscreen.setOnClickListener(mOnCaptionButtonClickListener); final View desktop = menu.findViewById(R.id.desktop_button); - desktop.setOnClickListener(mOnCaptionButtonClickListener); + if (DesktopModeStatus.isProto2Enabled()) { + desktop.setOnClickListener(mOnCaptionButtonClickListener); + } else if (DesktopModeStatus.isProto1Enabled()) { + desktop.setVisibility(View.GONE); + } final View split = menu.findViewById(R.id.split_screen_button); split.setOnClickListener(mOnCaptionButtonClickListener); + final View close = menu.findViewById(R.id.close_button); + close.setOnClickListener(mOnCaptionButtonClickListener); + final View collapse = menu.findViewById(R.id.collapse_menu_button); + collapse.setOnClickListener(mOnCaptionButtonClickListener); + menu.setOnTouchListener(mOnCaptionTouchListener); + + String packageName = mTaskInfo.baseActivity.getPackageName(); + PackageManager pm = mContext.getApplicationContext().getPackageManager(); + // TODO(b/268363572): Use IconProvider or BaseIconCache to set drawable/name. + try { + ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, + PackageManager.ApplicationInfoFlags.of(0)); + final ImageView appIcon = menu.findViewById(R.id.application_icon); + appIcon.setImageDrawable(pm.getApplicationIcon(applicationInfo)); + final TextView appName = menu.findViewById(R.id.application_name); + appName.setText(pm.getApplicationLabel(applicationInfo)); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Package not found: " + packageName, e); + } } /** * Sets caption visibility based on task focus. - * + * Note: Only applicable to Desktop Proto 1; Proto 2 only closes handle menu on focus loss * @param visible whether or not the caption should be visible */ private void setCaptionVisibility(boolean visible) { + if (!visible) closeHandleMenu(); + if (!DesktopModeStatus.isProto1Enabled()) return; final int v = visible ? View.VISIBLE : View.GONE; final View captionView = mResult.mRootView.findViewById(R.id.desktop_mode_caption); captionView.setVisibility(v); - if (!visible) closeHandleMenu(); + } /** @@ -244,8 +279,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin * Show or hide buttons */ void setButtonVisibility(boolean visible) { - final int visibility = visible ? View.VISIBLE : View.GONE; + final int visibility = visible && DesktopModeStatus.isProto1Enabled() + ? View.VISIBLE : View.GONE; final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption); + final View back = caption.findViewById(R.id.back_button); + final View close = caption.findViewById(R.id.close_window); + back.setVisibility(visibility); + close.setVisibility(visibility); final int buttonTintColorRes = mDesktopActive ? R.color.decor_button_dark_color : R.color.decor_button_light_color; @@ -254,13 +294,33 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final View handle = caption.findViewById(R.id.caption_handle); final VectorDrawable handleBackground = (VectorDrawable) handle.getBackground(); handleBackground.setTintList(buttonTintColor); - caption.getBackground().setTint(visible ? Color.WHITE : Color.TRANSPARENT); } boolean isHandleMenuActive() { return mHandleMenu != null; } + void setCaptionColor(int captionColor) { + if (mResult.mRootView == null) { + return; + } + + final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption); + final GradientDrawable captionDrawable = (GradientDrawable) caption.getBackground(); + captionDrawable.setColor(captionColor); + + final int buttonTintColorRes = + Color.valueOf(captionColor).luminance() < 0.5 + ? R.color.decor_button_light_color + : R.color.decor_button_dark_color; + final ColorStateList buttonTintColor = + caption.getResources().getColorStateList(buttonTintColorRes, null /* theme */); + + final View handle = caption.findViewById(R.id.caption_handle); + final Drawable handleBackground = handle.getBackground(); + handleBackground.setTintList(buttonTintColor); + } + private void closeDragResizeListener() { if (mDragResizeListener == null) { return; @@ -277,16 +337,21 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final Resources resources = mDecorWindowContext.getResources(); final int captionWidth = mTaskInfo.getConfiguration() .windowConfiguration.getBounds().width(); - final int menuWidth = loadDimensionPixelSize( - resources, mCaptionMenuWidthId); - final int height = loadDimensionPixelSize( - resources, mRelayoutParams.mCaptionHeightId); + final int menuWidth = loadDimensionPixelSize(resources, mHandleMenuWidthId); + final int menuHeight = loadDimensionPixelSize(resources, mCaptionMenuHeightId); + + // Elevation gives the appearance of a changed x/y coordinate; this is to fix that + int elevationOffset = 2 * loadDimensionPixelSize(resources, + R.dimen.caption_menu_elevation); + final int x = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menuWidth / 2) - - mResult.mDecorContainerOffsetX; - final int y = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY; + - mResult.mDecorContainerOffsetX - elevationOffset; + final int y = + mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY - elevationOffset; + mHandleMenuPosition.set(x, y); String namePrefix = "Caption Menu"; mHandleMenu = addWindow(R.layout.desktop_mode_decor_handle_menu, namePrefix, t, x, y, - menuWidth, height); + menuWidth, menuHeight, 2 * elevationOffset); mSyncQueue.runInSync(transaction -> { transaction.merge(t); t.close(); @@ -315,10 +380,17 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin * @param ev the tapped point to compare against */ void closeHandleMenuIfNeeded(MotionEvent ev) { - if (isHandleMenuActive()) { - if (!checkEventInCaptionView(ev, R.id.desktop_mode_caption)) { - closeHandleMenu(); - } + if (!isHandleMenuActive()) return; + + // When this is called before the layout is fully inflated, width will be 0. + // Menu is not visible in this scenario, so skip the check if that is the case. + if (mHandleMenu.mWindowViewHost.getView().getWidth() == 0) return; + + PointF inputPoint = offsetCaptionLocation(ev); + if (!pointInView(mHandleMenu.mWindowViewHost.getView(), + inputPoint.x - mHandleMenuPosition.x - mResult.mDecorContainerOffsetX, + inputPoint.y - mHandleMenuPosition.y - mResult.mDecorContainerOffsetY)) { + closeHandleMenu(); } } @@ -380,12 +452,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final int menuX = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menu.getWidth() / 2); final PointF inputPoint = new PointF(ev.getX() - menuX, ev.getY()); - final View fullscreen = menu.findViewById(R.id.fullscreen_button); - if (clickIfPointInView(inputPoint, fullscreen)) return; - final View desktop = menu.findViewById(R.id.desktop_button); - if (clickIfPointInView(inputPoint, desktop)) return; - final View split = menu.findViewById(R.id.split_screen_button); - if (clickIfPointInView(inputPoint, split)) return; + final View collapse = menu.findViewById(R.id.collapse_menu_button); + if (clickIfPointInView(inputPoint, collapse)) return; } } 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 62b72f377cdb..ae685ad4b8d9 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 @@ -391,10 +391,11 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * @param yPos y position of new window * @param width width of new window * @param height height of new window + * @param cropPadding padding to add to window crop to ensure shadows display properly * @return */ - AdditionalWindow addWindow(int layoutId, String namePrefix, - SurfaceControl.Transaction t, int xPos, int yPos, int width, int height) { + AdditionalWindow addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t, + int xPos, int yPos, int width, int height, int cropPadding) { final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); SurfaceControl windowSurfaceControl = builder .setName(namePrefix + " of Task=" + mTaskInfo.taskId) @@ -405,7 +406,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> t.setPosition( windowSurfaceControl, xPos, yPos) - .setWindowCrop(windowSurfaceControl, width, height) + .setWindowCrop(windowSurfaceControl, width + cropPadding, height + cropPadding) .show(windowSurfaceControl); final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height, @@ -426,6 +427,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> RunningTaskInfo mRunningTaskInfo; int mLayoutResId; int mCaptionHeightId; + int mCaptionWidthId; int mShadowRadiusId; int mOutsetTopId; @@ -451,6 +453,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> void reset() { mLayoutResId = Resources.ID_NULL; mCaptionHeightId = Resources.ID_NULL; + mCaptionWidthId = Resources.ID_NULL; mShadowRadiusId = Resources.ID_NULL; mOutsetTopId = Resources.ID_NULL; 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 index 7997a7ed7f7f..43f8f7b074bf 100644 --- 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 @@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER; @@ -446,7 +447,7 @@ public class DesktopModeControllerTest extends ShellTestCase { final ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass( WindowContainerTransaction.class); if (Transitions.ENABLE_SHELL_TRANSITIONS) { - verify(mTransitions).startTransition(eq(TRANSIT_TO_FRONT), arg.capture(), any()); + verify(mTransitions).startTransition(eq(TRANSIT_NONE), arg.capture(), any()); } else { verify(mShellTaskOrganizer).applyTransaction(arg.capture()); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index f16beeed57a3..95e78a8b7bcc 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -26,6 +26,8 @@ import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.os.Binder import android.testing.AndroidTestingRunner import android.view.WindowManager +import android.view.WindowManager.TRANSIT_CHANGE +import android.view.WindowManager.TRANSIT_NONE import android.view.WindowManager.TRANSIT_OPEN import android.view.WindowManager.TRANSIT_TO_FRONT import android.window.TransitionRequestInfo @@ -55,6 +57,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.eq import org.mockito.ArgumentMatchers.isNull import org.mockito.Mock import org.mockito.Mockito @@ -141,7 +144,7 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.showDesktopApps() - val wct = getLatestWct() + val wct = getLatestWct(expectTransition = TRANSIT_NONE) assertThat(wct.hierarchyOps).hasSize(3) // Expect order to be from bottom: home, task1, task2 wct.assertReorderAt(index = 0, homeTask) @@ -159,7 +162,7 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.showDesktopApps() - val wct = getLatestWct() + val wct = getLatestWct(expectTransition = TRANSIT_NONE) assertThat(wct.hierarchyOps).hasSize(3) // Expect order to be from bottom: home, task1, task2 wct.assertReorderAt(index = 0, homeTask) @@ -177,7 +180,7 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.showDesktopApps() - val wct = getLatestWct() + val wct = getLatestWct(expectTransition = TRANSIT_NONE) assertThat(wct.hierarchyOps).hasSize(3) // Expect order to be from bottom: home, task1, task2 wct.assertReorderAt(index = 0, homeTask) @@ -191,7 +194,7 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.showDesktopApps() - val wct = getLatestWct() + val wct = getLatestWct(expectTransition = TRANSIT_NONE) assertThat(wct.hierarchyOps).hasSize(1) wct.assertReorderAt(index = 0, homeTask) } @@ -221,7 +224,7 @@ class DesktopTasksControllerTest : ShellTestCase() { fun moveToDesktop() { val task = setUpFullscreenTask() controller.moveToDesktop(task) - val wct = getLatestWct() + val wct = getLatestWct(expectTransition = TRANSIT_CHANGE) assertThat(wct.changes[task.token.asBinder()]?.windowingMode) .isEqualTo(WINDOWING_MODE_FREEFORM) } @@ -241,7 +244,7 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.moveToDesktop(fullscreenTask) - with(getLatestWct()) { + with(getLatestWct(expectTransition = TRANSIT_CHANGE)) { assertThat(hierarchyOps).hasSize(3) assertReorderSequence(homeTask, freeformTask, fullscreenTask) assertThat(changes[fullscreenTask.token.asBinder()]?.windowingMode) @@ -253,7 +256,7 @@ class DesktopTasksControllerTest : ShellTestCase() { fun moveToFullscreen() { val task = setUpFreeformTask() controller.moveToFullscreen(task) - val wct = getLatestWct() + val wct = getLatestWct(expectTransition = TRANSIT_CHANGE) assertThat(wct.changes[task.token.asBinder()]?.windowingMode) .isEqualTo(WINDOWING_MODE_FULLSCREEN) } @@ -415,10 +418,12 @@ class DesktopTasksControllerTest : ShellTestCase() { desktopModeTaskRepository.updateVisibleFreeformTasks(task.taskId, visible = false) } - private fun getLatestWct(): WindowContainerTransaction { + private fun getLatestWct( + @WindowManager.TransitionType expectTransition: Int = TRANSIT_OPEN + ): WindowContainerTransaction { val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java) if (ENABLE_SHELL_TRANSITIONS) { - verify(transitions).startTransition(anyInt(), arg.capture(), isNull()) + verify(transitions).startTransition(eq(expectTransition), arg.capture(), isNull()) } else { verify(shellTaskOrganizer).applyTransaction(arg.capture()) } 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 2f5263cf11d8..b80edcece512 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 @@ -431,7 +431,7 @@ public class WindowDecorationTests extends ShellTestCase { verify(additionalWindowSurfaceBuilder).setParent(decorContainerSurface); verify(additionalWindowSurfaceBuilder).build(); verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 20, 40); - verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, 432, 64); + verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, 442, 74); verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface); verify(mMockSurfaceControlViewHostFactory, Mockito.times(2)) .create(any(), eq(defaultDisplay), any()); @@ -565,7 +565,7 @@ public class WindowDecorationTests extends ShellTestCase { mMockSurfaceControlAddWindowT, x - mRelayoutResult.mDecorContainerOffsetX, y - mRelayoutResult.mDecorContainerOffsetY, - width, height); + width, height, 10); return additionalWindow; } } diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp index 90c4440c8339..2ab7a58556a2 100644 --- a/libs/hwui/pipeline/skia/ShaderCache.cpp +++ b/libs/hwui/pipeline/skia/ShaderCache.cpp @@ -174,14 +174,13 @@ void set(BlobCache* cache, const void* key, size_t keySize, const void* value, s void ShaderCache::saveToDiskLocked() { ATRACE_NAME("ShaderCache::saveToDiskLocked"); - if (mInitialized && mBlobCache && mSavePending) { + if (mInitialized && mBlobCache) { if (mIDHash.size()) { auto key = sIDKey; set(mBlobCache.get(), &key, sizeof(key), mIDHash.data(), mIDHash.size()); } mBlobCache->writeToFile(); } - mSavePending = false; } void ShaderCache::store(const SkData& key, const SkData& data, const SkString& /*description*/) { @@ -224,10 +223,10 @@ void ShaderCache::store(const SkData& key, const SkData& data, const SkString& / } set(bc, key.data(), keySize, value, valueSize); - if (!mSavePending && mDeferredSaveDelay > 0) { + if (!mSavePending && mDeferredSaveDelayMs > 0) { mSavePending = true; std::thread deferredSaveThread([this]() { - sleep(mDeferredSaveDelay); + usleep(mDeferredSaveDelayMs * 1000); // milliseconds to microseconds std::lock_guard<std::mutex> lock(mMutex); // Store file on disk if there a new shader or Vulkan pipeline cache size changed. if (mCacheDirty || mNewPipelineCacheSize != mOldPipelineCacheSize) { @@ -236,6 +235,7 @@ void ShaderCache::store(const SkData& key, const SkData& data, const SkString& / mTryToStorePipelineCache = false; mCacheDirty = false; } + mSavePending = false; }); deferredSaveThread.detach(); } diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h index 3e0fd5164011..4e3eb816da29 100644 --- a/libs/hwui/pipeline/skia/ShaderCache.h +++ b/libs/hwui/pipeline/skia/ShaderCache.h @@ -153,7 +153,8 @@ private: * pending. Each time a key/value pair is inserted into the cache via * load, a deferred save is initiated if one is not already pending. * This will wait some amount of time and then trigger a save of the cache - * contents to disk. + * contents to disk, unless mDeferredSaveDelayMs is 0 in which case saving + * is disabled. */ bool mSavePending = false; @@ -163,9 +164,11 @@ private: size_t mObservedBlobValueSize = 20 * 1024; /** - * The time in seconds to wait before saving newly inserted cache entries. + * The time in milliseconds to wait before saving newly inserted cache entries. + * + * WARNING: setting this to 0 will disable writing the cache to disk. */ - unsigned int mDeferredSaveDelay = 4; + unsigned int mDeferredSaveDelayMs = 4 * 1000; /** * "mMutex" is the mutex used to prevent concurrent access to the member diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 59c914f0198c..4ceb13eb0e75 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -278,6 +278,11 @@ void DrawFrameTask::unblockUiThread() { mSignal.signal(); } +void DrawFrameTask::createHintSession(pid_t uiThreadId, pid_t renderThreadId) { + if (mHintSessionWrapper) return; + mHintSessionWrapper.emplace(uiThreadId, renderThreadId); +} + DrawFrameTask::HintSessionWrapper::HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId) { if (!Properties::useHintManager) return; if (uiThreadId < 0 || renderThreadId < 0) return; diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index d6fc292d5900..b135a215d180 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -90,6 +90,8 @@ public: void forceDrawNextFrame() { mForceDrawFrame = true; } + void createHintSession(pid_t uiThreadId, pid_t renderThreadId); + private: class HintSessionWrapper { public: diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index a44b498c81c1..d9b650c1ff37 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -38,11 +38,18 @@ namespace renderthread { RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) : mRenderThread(RenderThread::getInstance()), mContext(nullptr) { - mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* { - return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory); + pid_t uiThreadId = pthread_gettid_np(pthread_self()); + pid_t renderThreadId = getRenderThreadTid(); + mContext = mRenderThread.queue().runSync([=, this]() -> CanvasContext* { + CanvasContext* context = + CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory); + if (context != nullptr) { + mRenderThread.queue().post( + [=] { mDrawFrameTask.createHintSession(uiThreadId, renderThreadId); }); + } + return context; }); - mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode, - pthread_gettid_np(pthread_self()), getRenderThreadTid()); + mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode, uiThreadId, renderThreadId); } RenderProxy::~RenderProxy() { diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp index 974d85a453db..7bcd45c6b643 100644 --- a/libs/hwui/tests/unit/ShaderCacheTests.cpp +++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +#include <GrDirectContext.h> +#include <Properties.h> +#include <SkData.h> +#include <SkRefCnt.h> #include <cutils/properties.h> #include <dirent.h> #include <errno.h> @@ -22,9 +26,12 @@ #include <stdlib.h> #include <sys/types.h> #include <utils/Log.h> + #include <cstdint> + #include "FileBlobCache.h" #include "pipeline/skia/ShaderCache.h" +#include "tests/common/TestUtils.h" using namespace android::uirenderer::skiapipeline; @@ -35,11 +42,38 @@ namespace skiapipeline { class ShaderCacheTestUtils { public: /** - * "setSaveDelay" sets the time in seconds to wait before saving newly inserted cache entries. - * If set to 0, then deferred save is disabled. + * Hack to reset all member variables of the given cache to their default / initial values. + * + * WARNING: this must be kept up to date manually, since ShaderCache's parent disables just + * reassigning a new instance. */ - static void setSaveDelay(ShaderCache& cache, unsigned int saveDelay) { - cache.mDeferredSaveDelay = saveDelay; + static void reinitializeAllFields(ShaderCache& cache) { + ShaderCache newCache = ShaderCache(); + std::lock_guard<std::mutex> lock(cache.mMutex); + // By order of declaration + cache.mInitialized = newCache.mInitialized; + cache.mBlobCache.reset(nullptr); + cache.mFilename = newCache.mFilename; + cache.mIDHash.clear(); + cache.mSavePending = newCache.mSavePending; + cache.mObservedBlobValueSize = newCache.mObservedBlobValueSize; + cache.mDeferredSaveDelayMs = newCache.mDeferredSaveDelayMs; + cache.mTryToStorePipelineCache = newCache.mTryToStorePipelineCache; + cache.mInStoreVkPipelineInProgress = newCache.mInStoreVkPipelineInProgress; + cache.mNewPipelineCacheSize = newCache.mNewPipelineCacheSize; + cache.mOldPipelineCacheSize = newCache.mOldPipelineCacheSize; + cache.mCacheDirty = newCache.mCacheDirty; + cache.mNumShadersCachedInRam = newCache.mNumShadersCachedInRam; + } + + /** + * "setSaveDelayMs" sets the time in milliseconds to wait before saving newly inserted cache + * entries. If set to 0, then deferred save is disabled, and "saveToDiskLocked" must be called + * manually, as seen in the "terminate" testing helper function. + */ + static void setSaveDelayMs(ShaderCache& cache, unsigned int saveDelayMs) { + std::lock_guard<std::mutex> lock(cache.mMutex); + cache.mDeferredSaveDelayMs = saveDelayMs; } /** @@ -48,8 +82,9 @@ public: */ static void terminate(ShaderCache& cache, bool saveContent) { std::lock_guard<std::mutex> lock(cache.mMutex); - cache.mSavePending = saveContent; - cache.saveToDiskLocked(); + if (saveContent) { + cache.saveToDiskLocked(); + } cache.mBlobCache = NULL; } @@ -60,6 +95,38 @@ public: static bool validateCache(ShaderCache& cache, std::vector<T> hash) { return cache.validateCache(hash.data(), hash.size() * sizeof(T)); } + + /** + * Waits until cache::mSavePending is false, checking every 0.1 ms *while the mutex is free*. + * + * Fails if there was no save pending, or if the cache was already being written to disk, or if + * timeoutMs is exceeded. + * + * Note: timeoutMs only guards against mSavePending getting stuck like in b/268205519, and + * cannot protect against mutex-based deadlock. Reaching timeoutMs implies something is broken, + * so setting it to a sufficiently large value will not delay execution in the happy state. + */ + static void waitForPendingSave(ShaderCache& cache, const int timeoutMs = 50) { + { + std::lock_guard<std::mutex> lock(cache.mMutex); + ASSERT_TRUE(cache.mSavePending); + } + bool saving = true; + float elapsedMilliseconds = 0; + while (saving) { + if (elapsedMilliseconds >= timeoutMs) { + FAIL() << "Timed out after waiting " << timeoutMs << " ms for a pending save"; + } + // This small (0.1 ms) delay is to avoid working too much while waiting for + // deferredSaveThread to take the mutex and start the disk write. + const int delayMicroseconds = 100; + usleep(delayMicroseconds); + elapsedMilliseconds += (float)delayMicroseconds / 1000; + + std::lock_guard<std::mutex> lock(cache.mMutex); + saving = cache.mSavePending; + } + } }; } /* namespace skiapipeline */ @@ -81,6 +148,18 @@ bool folderExist(const std::string& folderName) { return false; } +/** + * Attempts to delete the given file, and asserts that either: + * 1. Deletion was successful, OR + * 2. The file did not exist. + * + * Tip: wrap calls to this in ASSERT_NO_FATAL_FAILURE(x) if a test should exit early if this fails. + */ +void deleteFileAssertSuccess(const std::string& filePath) { + int deleteResult = remove(filePath.c_str()); + ASSERT_TRUE(0 == deleteResult || ENOENT == errno); +} + inline bool checkShader(const sk_sp<SkData>& shader1, const sk_sp<SkData>& shader2) { return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size() && 0 == memcmp(shader1->data(), shader2->data(), shader1->size()); @@ -91,6 +170,10 @@ inline bool checkShader(const sk_sp<SkData>& shader, const char* program) { return checkShader(shader, shader2); } +inline bool checkShader(const sk_sp<SkData>& shader, const std::string& program) { + return checkShader(shader, program.c_str()); +} + template <typename T> bool checkShader(const sk_sp<SkData>& shader, std::vector<T>& program) { sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size() * sizeof(T)); @@ -101,6 +184,10 @@ void setShader(sk_sp<SkData>& shader, const char* program) { shader = SkData::MakeWithCString(program); } +void setShader(sk_sp<SkData>& shader, const std::string& program) { + setShader(shader, program.c_str()); +} + template <typename T> void setShader(sk_sp<SkData>& shader, std::vector<T>& buffer) { shader = SkData::MakeWithCopy(buffer.data(), buffer.size() * sizeof(T)); @@ -124,13 +211,13 @@ TEST(ShaderCacheTest, testWriteAndRead) { std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; // remove any test files from previous test run - int deleteFile = remove(cacheFile1.c_str()); - ASSERT_TRUE(0 == deleteFile || ENOENT == errno); + ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1)); + ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2)); std::srand(0); // read the cache from a file that does not exist ShaderCache::get().setFilename(cacheFile1.c_str()); - ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save + ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 0); // disable deferred save ShaderCache::get().initShaderDiskCache(); // read a key - should not be found since the cache is empty @@ -184,7 +271,8 @@ TEST(ShaderCacheTest, testWriteAndRead) { ASSERT_TRUE(checkShader(outVS2, dataBuffer)); ShaderCacheTestUtils::terminate(ShaderCache::get(), false); - remove(cacheFile1.c_str()); + ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1)); + ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2)); } TEST(ShaderCacheTest, testCacheValidation) { @@ -196,13 +284,13 @@ TEST(ShaderCacheTest, testCacheValidation) { std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; // remove any test files from previous test run - int deleteFile = remove(cacheFile1.c_str()); - ASSERT_TRUE(0 == deleteFile || ENOENT == errno); + ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1)); + ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2)); std::srand(0); // generate identity and read the cache from a file that does not exist ShaderCache::get().setFilename(cacheFile1.c_str()); - ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save + ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 0); // disable deferred save std::vector<uint8_t> identity(1024); genRandomData(identity); ShaderCache::get().initShaderDiskCache( @@ -276,7 +364,81 @@ TEST(ShaderCacheTest, testCacheValidation) { } ShaderCacheTestUtils::terminate(ShaderCache::get(), false); - remove(cacheFile1.c_str()); + ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1)); + ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2)); +} + +using namespace android::uirenderer; +RENDERTHREAD_SKIA_PIPELINE_TEST(ShaderCacheTest, testOnVkFrameFlushed) { + if (Properties::getRenderPipelineType() != RenderPipelineType::SkiaVulkan) { + // RENDERTHREAD_SKIA_PIPELINE_TEST declares both SkiaVK and SkiaGL variants. + GTEST_SKIP() << "This test is only applicable to RenderPipelineType::SkiaVulkan"; + } + if (!folderExist(getExternalStorageFolder())) { + // Don't run the test if external storage folder is not available + return; + } + std::string cacheFile = getExternalStorageFolder() + "/shaderCacheTest"; + GrDirectContext* grContext = renderThread.getGrContext(); + + // Remove any test files from previous test run + ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile)); + + // The first iteration of this loop is to save an initial VkPipelineCache data blob to disk, + // which sets up the second iteration for a common scenario of comparing a "new" VkPipelineCache + // blob passed to "store" against the same blob that's already in the persistent cache from a + // previous launch. "reinitializeAllFields" is critical to emulate each iteration being as close + // to the state of a freshly launched app as possible, as the initial values of member variables + // like mInStoreVkPipelineInProgress and mOldPipelineCacheSize are critical to catch issues + // such as b/268205519 + for (int flushIteration = 1; flushIteration <= 2; flushIteration++) { + SCOPED_TRACE("Frame flush iteration " + std::to_string(flushIteration)); + // Reset *all* in-memory data and reload the cache from disk. + ShaderCacheTestUtils::reinitializeAllFields(ShaderCache::get()); + ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 10); // Delay must be > 0 to save. + ShaderCache::get().setFilename(cacheFile.c_str()); + ShaderCache::get().initShaderDiskCache(); + + // 1st iteration: store pipeline data to be read back on a subsequent "boot" of the "app". + // 2nd iteration: ensure that an initial frame flush (without storing any shaders) given the + // same pipeline data that's already on disk doesn't break the cache. + ShaderCache::get().onVkFrameFlushed(grContext); + ASSERT_NO_FATAL_FAILURE(ShaderCacheTestUtils::waitForPendingSave(ShaderCache::get())); + } + + constexpr char shader1[] = "sassas"; + constexpr char shader2[] = "someVS"; + constexpr int numIterations = 3; + // Also do n iterations of separate "store some shaders then flush the frame" pairs to just + // double-check the cache also doesn't get stuck from that use case. + for (int saveIteration = 1; saveIteration <= numIterations; saveIteration++) { + SCOPED_TRACE("Shader save iteration " + std::to_string(saveIteration)); + // Write twice to the in-memory cache, which should start a deferred save with both queued. + sk_sp<SkData> inVS; + setShader(inVS, shader1 + std::to_string(saveIteration)); + ShaderCache::get().store(GrProgramDescTest(100), *inVS.get(), SkString()); + setShader(inVS, shader2 + std::to_string(saveIteration)); + ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString()); + + // Simulate flush to also save latest pipeline info. + ShaderCache::get().onVkFrameFlushed(grContext); + ASSERT_NO_FATAL_FAILURE(ShaderCacheTestUtils::waitForPendingSave(ShaderCache::get())); + } + + // Reload from disk to ensure saving succeeded. + ShaderCacheTestUtils::terminate(ShaderCache::get(), false); + ShaderCache::get().initShaderDiskCache(); + + // Read twice, ensure equal to last store. + sk_sp<SkData> outVS; + ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>()); + ASSERT_TRUE(checkShader(outVS, shader1 + std::to_string(numIterations))); + ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); + ASSERT_TRUE(checkShader(outVS, shader2 + std::to_string(numIterations))); + + // Clean up. + ShaderCacheTestUtils::terminate(ShaderCache::get(), false); + ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile)); } } // namespace diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml index 03c32ba6640b..41f680e3b0c4 100644 --- a/packages/CompanionDeviceManager/res/values-eu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml @@ -17,10 +17,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"Gailu osagarriaren kudeatzailea"</string> - <string name="confirmation_title" msgid="3785000297483688997">"Eman <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> atzitzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string> + <string name="confirmation_title" msgid="3785000297483688997">"Eman <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> erabiltzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string> <string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string> <string name="chooser_title" msgid="2262294130493605839">"Aukeratu <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> - <string name="summary_watch" msgid="3002344206574997652">"Aplikazio hau <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kudeatzeko beharrezkoa da. Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak, egutegia, deien erregistroa eta inguruko gailuak atzitzeko baimenak izango ditu <xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioak."</string> + <string name="summary_watch" msgid="3002344206574997652">"Aplikazio hau <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kudeatzeko beharrezkoa da. Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak, egutegia, deien erregistroa eta inguruko gailuak erabiltzeko baimenak izango ditu <xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioak."</string> <string name="permission_apps" msgid="6142133265286656158">"Aplikazioak"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Igorri zuzenean telefonoko aplikazioak"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Eman informazioa telefonotik hartzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string> @@ -28,21 +28,21 @@ <string name="helper_summary_app_streaming" msgid="5977509499890099">"Gailu batetik bestera aplikazioak igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuaren izenean"</string> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> - <string name="title_computer" msgid="4693714143506569253">"Eman telefonoko informazio hau atzitzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string> + <string name="title_computer" msgid="4693714143506569253">"Eman telefonoko informazio hau erabiltzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Jakinarazpenak"</string> <string name="permission_notification_summary" msgid="884075314530071011">"Jakinarazpen guztiak irakur ditzake; besteak beste, kontaktuak, mezuak, argazkiak eta antzeko informazioa"</string> <string name="permission_storage" msgid="6831099350839392343">"Argazkiak eta multimedia-edukia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string> - <string name="helper_summary_computer" msgid="9050724687678157852">"Telefonoko argazkiak, multimedia-edukia eta jakinarazpenak atzitzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuaren izenean"</string> + <string name="helper_summary_computer" msgid="9050724687678157852">"Telefonoko argazkiak, multimedia-edukia eta jakinarazpenak erabiltzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuaren izenean"</string> <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Eman baimena"</string> <string name="consent_no" msgid="2640796915611404382">"Ez eman baimenik"</string> <string name="consent_back" msgid="2560683030046918882">"Atzera"</string> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferitu aplikazio-baimenak erlojura"</string> - <string name="permission_sync_summary" msgid="8873391306499120778">"Erlojua errazago konfiguratzeko, konfigurazio-prozesua abian zen bitartean erlojuan instalatutako aplikazioek telefonoak darabiltzan baimen berak erabiliko dituzte.\n\n Baliteke baimen horien artean erlojuaren mikrofonoa eta kokapena atzitzeko baimenak egotea."</string> + <string name="permission_sync_summary" msgid="8873391306499120778">"Erlojua errazago konfiguratzeko, konfigurazio-prozesua abian zen bitartean erlojuan instalatutako aplikazioek telefonoak darabiltzan baimen berak erabiliko dituzte.\n\n Baliteke baimen horien artean erlojuaren mikrofonoa eta kokapena erabiltzeko baimenak egotea."</string> <string name="vendor_icon_description" msgid="4445875290032225965">"Aplikazioaren ikonoa"</string> <string name="vendor_header_button_description" msgid="6566660389500630608">"Informazio gehiagorako botoia"</string> </resources> diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml index 4ee4323daebd..483a5224b999 100644 --- a/packages/PrintSpooler/res/values-ca/strings.xml +++ b/packages/PrintSpooler/res/values-ca/strings.xml @@ -56,7 +56,7 @@ <string name="print_select_printer" msgid="7388760939873368698">"Selecciona una impressora"</string> <string name="print_forget_printer" msgid="5035287497291910766">"Oblida la impressora"</string> <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868"> - <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item> + <item quantity="many">S\'han trobat <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item> <item quantity="other">S\'han trobat <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item> <item quantity="one">S\'ha trobat <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item> </plurals> @@ -77,7 +77,7 @@ <string name="disabled_services_title" msgid="7313253167968363211">"Serveis desactivats"</string> <string name="all_services_title" msgid="5578662754874906455">"Tots els serveis"</string> <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138"> - <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item> + <item quantity="many">Instal·la\'l per detectar <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item> <item quantity="other">Instal·la\'l per detectar <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item> <item quantity="one">Instal·la\'l per detectar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item> </plurals> diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml index 90c1937a2891..476614b1a60d 100644 --- a/packages/PrintSpooler/res/values-es-rUS/strings.xml +++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml @@ -56,7 +56,7 @@ <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string> <string name="print_forget_printer" msgid="5035287497291910766">"No recordar impresora"</string> <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868"> - <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item> + <item quantity="many">Se encontraron <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras.</item> <item quantity="other">Se encontraron <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras.</item> <item quantity="one">Se encontró <xliff:g id="COUNT_0">%1$s</xliff:g> impresora.</item> </plurals> @@ -77,7 +77,7 @@ <string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string> <string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string> <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138"> - <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item> + <item quantity="many">Instala para ver <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item> <item quantity="other">Instala para ver <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item> <item quantity="one">Instala para ver <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item> </plurals> diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml index 18e56dbcd6fc..507b2a7a8f25 100644 --- a/packages/PrintSpooler/res/values-es/strings.xml +++ b/packages/PrintSpooler/res/values-es/strings.xml @@ -56,7 +56,7 @@ <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string> <string name="print_forget_printer" msgid="5035287497291910766">"Olvidar impresora"</string> <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868"> - <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item> + <item quantity="many">Se han encontrado <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item> <item quantity="other">Se han encontrado <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item> <item quantity="one">Se ha encontrado <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item> </plurals> @@ -77,7 +77,7 @@ <string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string> <string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string> <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138"> - <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item> + <item quantity="many">Instalar para descubrir <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item> <item quantity="other">Instalar para descubrir <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item> <item quantity="one">Instalar para descubrir <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item> </plurals> diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml index 082c148746a3..5298f8b329ba 100644 --- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml +++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml @@ -57,7 +57,7 @@ <string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string> <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868"> <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item> - <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item> + <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvées</item> <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvées</item> </plurals> <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string> @@ -78,7 +78,7 @@ <string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string> <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138"> <item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item> - <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item> + <item quantity="many">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item> <item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item> </plurals> <string name="printing_notification_title_template" msgid="295903957762447362">"Impression de <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> en cours…"</string> diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml index 560c5dcfe924..4b7e83c85953 100644 --- a/packages/PrintSpooler/res/values-fr/strings.xml +++ b/packages/PrintSpooler/res/values-fr/strings.xml @@ -57,7 +57,7 @@ <string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string> <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868"> <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item> - <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item> + <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes trouvées</item> <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes trouvées</item> </plurals> <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string> @@ -78,7 +78,7 @@ <string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string> <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138"> <item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item> - <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item> + <item quantity="many">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item> <item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item> </plurals> <string name="printing_notification_title_template" msgid="295903957762447362">"Impression de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string> diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml index 569bbc2ef045..2a64d3debf58 100644 --- a/packages/PrintSpooler/res/values-it/strings.xml +++ b/packages/PrintSpooler/res/values-it/strings.xml @@ -56,7 +56,7 @@ <string name="print_select_printer" msgid="7388760939873368698">"Seleziona stampante"</string> <string name="print_forget_printer" msgid="5035287497291910766">"Elimina stampante"</string> <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868"> - <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item> + <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> stampanti trovate</item> <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> stampanti trovate</item> <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> stampante trovata</item> </plurals> @@ -77,7 +77,7 @@ <string name="disabled_services_title" msgid="7313253167968363211">"Servizi disattivati"</string> <string name="all_services_title" msgid="5578662754874906455">"Tutti i servizi"</string> <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138"> - <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item> + <item quantity="many">Installa per rilevare <xliff:g id="COUNT_1">%1$s</xliff:g> stampanti</item> <item quantity="other">Installa per rilevare <xliff:g id="COUNT_1">%1$s</xliff:g> stampanti</item> <item quantity="one">Installa per rilevare <xliff:g id="COUNT_0">%1$s</xliff:g> stampante</item> </plurals> diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml index 3b460a1fe6dd..855701bca9fc 100644 --- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml +++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml @@ -57,7 +57,7 @@ <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string> <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868"> <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item> - <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item> + <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item> <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item> </plurals> <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string> @@ -78,7 +78,7 @@ <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string> <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138"> <item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item> - <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item> + <item quantity="many">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item> <item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item> </plurals> <string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml index 8c1087e463a0..c9a52a87f9a6 100644 --- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml +++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml @@ -56,7 +56,7 @@ <string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string> <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string> <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868"> - <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item> + <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item> <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item> <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item> </plurals> @@ -77,7 +77,7 @@ <string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string> <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string> <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138"> - <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item> + <item quantity="many">Instale para detetar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item> <item quantity="other">Instale para detetar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item> <item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item> </plurals> diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml index 3b460a1fe6dd..855701bca9fc 100644 --- a/packages/PrintSpooler/res/values-pt/strings.xml +++ b/packages/PrintSpooler/res/values-pt/strings.xml @@ -57,7 +57,7 @@ <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string> <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868"> <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item> - <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item> + <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item> <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item> </plurals> <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string> @@ -78,7 +78,7 @@ <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string> <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138"> <item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item> - <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item> + <item quantity="many">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item> <item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item> </plurals> <string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml index b6f15903ecbd..3062e7dd44a4 100644 --- a/packages/SettingsLib/res/values-ca/arrays.xml +++ b/packages/SettingsLib/res/values-ca/arrays.xml @@ -232,7 +232,7 @@ <item msgid="8612549335720461635">"4K (segur)"</item> <item msgid="7322156123728520872">"4K (ampliat)"</item> <item msgid="7735692090314849188">"4K (ampliat, segur)"</item> - <item msgid="7346816300608639624">"720p, 1080p (pantalla doble)"</item> + <item msgid="7346816300608639624">"720p, 1080p (pantalla dual)"</item> </string-array> <string-array name="enable_opengl_traces_entries"> <item msgid="4433736508877934305">"Cap"</item> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index ff042706cf58..fe97f345229f 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -587,7 +587,7 @@ <string name="user_need_lock_message" msgid="4311424336209509301">"Para poder crear un perfil restringido, debes configurar una pantalla de bloqueo que proteja tus aplicaciones y datos personales."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Establecer bloqueo"</string> <string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string> - <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario…"</string> + <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario nuevo…"</string> <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Creando nuevo invitado…"</string> <string name="add_user_failed" msgid="4809887794313944872">"No se ha podido crear el usuario"</string> <string name="add_guest_failed" msgid="8074548434469843443">"No se ha podido crear un nuevo invitado"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index aede28a316bf..145dc5d997a5 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -574,7 +574,7 @@ <string name="user_add_user_title" msgid="5457079143694924885">"Vil du legge til en ny bruker?"</string> <string name="user_add_user_message_long" msgid="1527434966294733380">"Du kan dele denne enheten med andre folk ved å opprette flere brukere. Hver bruker har sin egen plass de kan tilpasse med apper, bakgrunner og annet. Brukere kan også justere enhetsinnstillinger, for eksempel Wifi, som påvirker alle.\n\nNår du legger til en ny bruker, må vedkommende angi innstillinger for plassen sin.\n\nAlle brukere kan oppdatere apper for alle andre brukere. Innstillinger og tjenester for tilgjengelighet overføres kanskje ikke til den nye brukeren."</string> <string name="user_add_user_message_short" msgid="3295959985795716166">"Når du legger til en ny bruker, må hen konfigurere sitt eget område.\n\nAlle brukere kan oppdatere apper for alle andre brukere."</string> - <string name="user_setup_dialog_title" msgid="8037342066381939995">"Konfigurere brukeren nå?"</string> + <string name="user_setup_dialog_title" msgid="8037342066381939995">"Vil du konfigurere brukeren?"</string> <string name="user_setup_dialog_message" msgid="269931619868102841">"Sørg for at brukeren er tilgjengelig for å konfigurere området sitt på enheten"</string> <string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Vil du konfigurere profilen nå?"</string> <string name="user_setup_button_setup_now" msgid="1708269547187760639">"Konfigurer nå"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 8ee274b2cd15..f29c7452b24f 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -573,7 +573,7 @@ <string name="user_add_profile_item_title" msgid="3111051717414643029">"Beperkt profiel"</string> <string name="user_add_user_title" msgid="5457079143694924885">"Nieuwe gebruiker toevoegen?"</string> <string name="user_add_user_message_long" msgid="1527434966294733380">"Je kunt dit apparaat met anderen delen door extra gebruikers te maken. Elke gebruiker heeft een eigen profiel met zelf gekozen apps, achtergrond, enzovoort. Gebruikers kunnen ook apparaatinstellingen aanpassen die van invloed zijn op alle gebruikers, zoals wifi.\n\nWanneer je een nieuwe gebruiker toevoegt, moet die persoon een eigen profiel instellen.\n\nElke gebruiker kan apps updaten voor alle andere gebruikers. Toegankelijkheidsinstellingen en -services worden mogelijk niet overgezet naar de nieuwe gebruiker."</string> - <string name="user_add_user_message_short" msgid="3295959985795716166">"Wanneer je een nieuwe gebruiker toevoegt, moet die persoon diens eigen profiel instellen.\n\nElke gebruiker kan apps updaten voor alle andere gebruikers."</string> + <string name="user_add_user_message_short" msgid="3295959985795716166">"Wanneer je een nieuwe gebruiker toevoegt, moet die persoon hun eigen profiel instellen.\n\nElke gebruiker kan apps updaten voor alle andere gebruikers."</string> <string name="user_setup_dialog_title" msgid="8037342066381939995">"Gebruiker nu instellen?"</string> <string name="user_setup_dialog_message" msgid="269931619868102841">"Zorg ervoor dat de persoon het apparaat kan overnemen om een profiel in te stellen"</string> <string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Profiel nu instellen?"</string> diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml index 663e8e4b14d8..ef664e99936f 100644 --- a/packages/SettingsLib/res/values/arrays.xml +++ b/packages/SettingsLib/res/values/arrays.xml @@ -660,4 +660,18 @@ <!-- Content descriptions for each of the images in the avatar_images array. --> <string-array name="avatar_image_descriptions"/> + <string-array name="entries_font_size"> + <item msgid="6490061470416867723">Small</item> + <item msgid="3579015730662088893">Default</item> + <item msgid="1678068858001018666">Large</item> + <item msgid="490158884605093126">Largest</item> + </string-array> + + <string-array name="entryvalues_font_size" translatable="false"> + <item>0.85</item> + <item>1.0</item> + <item>1.15</item> + <item>1.30</item> + </string-array> + </resources> diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 252915703511..ed62c5f012bc 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -204,6 +204,45 @@ filegroup { path: "tests/utils/src", } +filegroup { + name: "SystemUI-tests-robolectric-pilots", + srcs: [ + // data + "tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt", + "tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt", + "tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt", + "tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt", + "tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt", + "tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt", + "tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt", + "tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt", + "tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt", + "tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt", + "tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt", + "tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt", + // domain + "tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt", + "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt", + "tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt", + "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt", + "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt", + "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt", + "tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt", + "tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceRegistry.kt", + "tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt", + "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt", + "tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt", + // ui + "tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt", + "tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt", + "tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt", + "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt", + "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt", + "tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt", + ], + path: "tests/src", +} + java_library { name: "SystemUI-tests-concurrency", srcs: [ @@ -315,8 +354,16 @@ android_app { defaults: [ "platform_app_defaults", "SystemUI_app_defaults", + "SystemUI_compose_defaults", ], manifest: "tests/AndroidManifest-base.xml", + + srcs: [ + "src/**/*.kt", + "src/**/*.java", + "src/**/I*.aidl", + ":ReleaseJavaFiles", + ], static_libs: [ "SystemUI-tests-base", ], @@ -330,6 +377,9 @@ android_app { certificate: "platform", privileged: true, resource_dirs: [], + kotlincflags: ["-Xjvm-default=all"], + + plugins: ["dagger2-compiler"], } android_robolectric_test { @@ -337,6 +387,13 @@ android_robolectric_test { srcs: [ "tests/robolectric/src/**/*.kt", "tests/robolectric/src/**/*.java", + ":SystemUI-tests-utils", + ":SystemUI-tests-robolectric-pilots", + ], + static_libs: [ + "androidx.test.uiautomator_uiautomator", + "androidx.test.ext.junit", + "inline-mockito-robolectric-prebuilt", ], libs: [ "android.test.runner", @@ -344,7 +401,9 @@ android_robolectric_test { "android.test.mock", "truth-prebuilt", ], - kotlincflags: ["-Xjvm-default=enable"], + + upstream: true, + instrumentation_for: "SystemUIRobo-stub", java_resource_dirs: ["tests/robolectric/config"], } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt index 5aa7769d5ace..42a86363bf01 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt @@ -33,13 +33,9 @@ import android.view.WindowInsets import android.view.WindowManager import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS import android.widget.FrameLayout -import android.window.OnBackInvokedDispatcher import com.android.internal.jank.InteractionJankMonitor import com.android.internal.jank.InteractionJankMonitor.CujType -import com.android.systemui.animation.back.BackAnimationSpec -import com.android.systemui.animation.back.applyTo -import com.android.systemui.animation.back.floatingSystemSurfacesForSysUi -import com.android.systemui.animation.back.onBackAnimationCallbackFrom +import com.android.systemui.util.registerAnimationOnBackInvoked import java.lang.IllegalArgumentException import kotlin.math.roundToInt @@ -798,7 +794,7 @@ private class AnimatedDialog( if (featureFlags.isPredictiveBackQsDialogAnim) { // TODO(b/265923095) Improve animations for QS dialogs on configuration change - registerOnBackInvokedCallback(targetView = dialogContentWithBackground) + dialog.registerAnimationOnBackInvoked(targetView = dialogContentWithBackground) } // Show the dialog. @@ -806,35 +802,6 @@ private class AnimatedDialog( moveSourceDrawingToDialog() } - private fun registerOnBackInvokedCallback(targetView: View) { - val metrics = targetView.resources.displayMetrics - - val onBackAnimationCallback = - onBackAnimationCallbackFrom( - backAnimationSpec = BackAnimationSpec.floatingSystemSurfacesForSysUi(metrics), - displayMetrics = metrics, // TODO(b/265060720): We could remove this - onBackProgressed = { backTransformation -> backTransformation.applyTo(targetView) }, - onBackInvoked = { dialog.dismiss() }, - ) - - val dispatcher = dialog.onBackInvokedDispatcher - targetView.addOnAttachStateChangeListener( - object : View.OnAttachStateChangeListener { - override fun onViewAttachedToWindow(v: View) { - dispatcher.registerOnBackInvokedCallback( - OnBackInvokedDispatcher.PRIORITY_DEFAULT, - onBackAnimationCallback - ) - } - - override fun onViewDetachedFromWindow(v: View) { - targetView.removeOnAttachStateChangeListener(this) - dispatcher.unregisterOnBackInvokedCallback(onBackAnimationCallback) - } - } - ) - } - private fun moveSourceDrawingToDialog() { if (decorView.viewRootImpl == null) { // Make sure that we have access to the dialog view root to move the drawing to the diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt index fdab7490e476..a08b59829de2 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt @@ -23,6 +23,7 @@ import android.animation.ValueAnimator import android.graphics.Canvas import android.graphics.Typeface import android.graphics.fonts.Font +import android.graphics.fonts.FontVariationAxis import android.text.Layout import android.util.SparseArray @@ -215,13 +216,40 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { textInterpolator.targetPaint.textSize = textSize } if (weight >= 0) { - // Paint#setFontVariationSettings creates Typeface instance from scratch. To reduce the - // memory impact, cache the typeface result. - textInterpolator.targetPaint.typeface = - typefaceCache.getOrElse(weight) { - textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight" - textInterpolator.targetPaint.typeface + val fontVariationArray = + FontVariationAxis.fromFontVariationSettings( + textInterpolator.targetPaint.fontVariationSettings + ) + if (fontVariationArray.isNullOrEmpty()) { + textInterpolator.targetPaint.typeface = + typefaceCache.getOrElse(weight) { + textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight" + textInterpolator.targetPaint.typeface + } + } else { + val idx = fontVariationArray.indexOfFirst { it.tag == "$TAG_WGHT" } + if (idx == -1) { + val updatedFontVariation = + textInterpolator.targetPaint.fontVariationSettings + ",'$TAG_WGHT' $weight" + textInterpolator.targetPaint.typeface = + typefaceCache.getOrElse(weight) { + textInterpolator.targetPaint.fontVariationSettings = + updatedFontVariation + textInterpolator.targetPaint.typeface + } + } else { + fontVariationArray[idx] = FontVariationAxis( + "$TAG_WGHT", weight.toFloat()) + val updatedFontVariation = + FontVariationAxis.toFontVariationSettings(fontVariationArray) + textInterpolator.targetPaint.typeface = + typefaceCache.getOrElse(weight) { + textInterpolator.targetPaint.fontVariationSettings = + updatedFontVariation + textInterpolator.targetPaint.typeface + } } + } } if (color != null) { textInterpolator.targetPaint.color = color diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtension.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtension.kt index 33d14b14c702..8740d1467296 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtension.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/OnBackAnimationCallbackExtension.kt @@ -16,15 +16,21 @@ package com.android.systemui.animation.back +import android.annotation.IntRange import android.util.DisplayMetrics +import android.view.View import android.window.BackEvent import android.window.OnBackAnimationCallback +import android.window.OnBackInvokedDispatcher +import android.window.OnBackInvokedDispatcher.Priority /** * Generates an [OnBackAnimationCallback] given a [backAnimationSpec]. [onBackProgressed] will be * called on each update passing the current [BackTransformation]. * * Optionally, you can specify [onBackStarted], [onBackInvoked], and [onBackCancelled] callbacks. + * + * @sample com.android.systemui.util.registerAnimationOnBackInvoked */ fun onBackAnimationCallbackFrom( backAnimationSpec: BackAnimationSpec, @@ -64,3 +70,34 @@ fun onBackAnimationCallbackFrom( } } } + +/** + * Register [OnBackAnimationCallback] when View is attached and unregister it when View is detached + * + * @sample com.android.systemui.util.registerAnimationOnBackInvoked + */ +fun View.registerOnBackInvokedCallbackOnViewAttached( + onBackInvokedDispatcher: OnBackInvokedDispatcher, + onBackAnimationCallback: OnBackAnimationCallback, + @Priority @IntRange(from = 0) priority: Int = OnBackInvokedDispatcher.PRIORITY_DEFAULT, +) { + addOnAttachStateChangeListener( + object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(v: View) { + onBackInvokedDispatcher.registerOnBackInvokedCallback( + priority, + onBackAnimationCallback + ) + } + + override fun onViewDetachedFromWindow(v: View) { + removeOnAttachStateChangeListener(this) + onBackInvokedDispatcher.unregisterOnBackInvokedCallback(onBackAnimationCallback) + } + } + ) + + if (isAttachedToWindow) { + onBackInvokedDispatcher.registerOnBackInvokedCallback(priority, onBackAnimationCallback) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableImageView.kt index 7bbfec7df9d8..a1d9d90523eb 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableImageView.kt @@ -15,7 +15,7 @@ * */ -package com.android.systemui.common.ui.view +package com.android.systemui.animation.view import android.content.Context import android.util.AttributeSet @@ -23,6 +23,7 @@ import android.widget.ImageView import com.android.systemui.animation.LaunchableView import com.android.systemui.animation.LaunchableViewDelegate +/** An [ImageView] that also implements [LaunchableView]. */ class LaunchableImageView : ImageView, LaunchableView { private val delegate = LaunchableViewDelegate( diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableLinearLayout.kt index 2edac528b037..bce262291f87 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableLinearLayout.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.common.ui.view +package com.android.systemui.animation.view import android.content.Context import android.util.AttributeSet diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableTextView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableTextView.kt new file mode 100644 index 000000000000..286996dcaeaa --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableTextView.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.animation.view + +import android.content.Context +import android.util.AttributeSet +import android.widget.TextView +import com.android.systemui.animation.LaunchableView +import com.android.systemui.animation.LaunchableViewDelegate + +/** A [TextView] that also implements [LaunchableView]. */ +class LaunchableTextView : TextView, LaunchableView { + private val delegate = + LaunchableViewDelegate( + this, + superSetVisibility = { super.setVisibility(it) }, + ) + + constructor(context: Context?) : super(context) + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) + constructor( + context: Context?, + attrs: AttributeSet?, + defStyleAttr: Int, + ) : super(context, attrs, defStyleAttr) + + override fun setShouldBlockVisibilityChanges(block: Boolean) { + delegate.setShouldBlockVisibilityChanges(block) + } + + override fun setVisibility(visibility: Int) { + delegate.setVisibility(visibility) + } +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt b/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt new file mode 100644 index 000000000000..428856dc5f30 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/util/Dialog.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util + +import android.app.Dialog +import android.view.View +import android.window.OnBackInvokedDispatcher +import com.android.systemui.animation.back.BackAnimationSpec +import com.android.systemui.animation.back.BackTransformation +import com.android.systemui.animation.back.applyTo +import com.android.systemui.animation.back.floatingSystemSurfacesForSysUi +import com.android.systemui.animation.back.onBackAnimationCallbackFrom +import com.android.systemui.animation.back.registerOnBackInvokedCallbackOnViewAttached + +/** + * Register on the Dialog's [OnBackInvokedDispatcher] an animation using the [BackAnimationSpec]. + * The [BackTransformation] will be applied on the [targetView]. + */ +@JvmOverloads +fun Dialog.registerAnimationOnBackInvoked( + targetView: View, + backAnimationSpec: BackAnimationSpec = + BackAnimationSpec.floatingSystemSurfacesForSysUi( + displayMetrics = targetView.resources.displayMetrics, + ), +) { + targetView.registerOnBackInvokedCallbackOnViewAttached( + onBackInvokedDispatcher = onBackInvokedDispatcher, + onBackAnimationCallback = + onBackAnimationCallbackFrom( + backAnimationSpec = backAnimationSpec, + displayMetrics = targetView.resources.displayMetrics, + onBackProgressed = { backTransformation -> backTransformation.applyTo(targetView) }, + onBackInvoked = { dismiss() }, + ), + ) +} diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt index a523cf10cf3b..ed6e6198f139 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -13,11 +13,13 @@ */ package com.android.systemui.shared.clocks +import android.app.ActivityManager +import android.app.UserSwitchObserver import android.content.Context import android.database.ContentObserver import android.graphics.drawable.Drawable import android.net.Uri -import android.os.Handler +import android.os.UserHandle import android.provider.Settings import android.util.Log import androidx.annotation.OpenForTesting @@ -29,17 +31,23 @@ import com.android.systemui.plugins.ClockProviderPlugin import com.android.systemui.plugins.ClockSettings import com.android.systemui.plugins.PluginListener import com.android.systemui.plugins.PluginManager +import com.android.systemui.util.Assert +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch -private val TAG = ClockRegistry::class.simpleName +private val TAG = ClockRegistry::class.simpleName!! private const val DEBUG = true /** ClockRegistry aggregates providers and plugins */ open class ClockRegistry( val context: Context, val pluginManager: PluginManager, - val handler: Handler, + val scope: CoroutineScope, + val mainDispatcher: CoroutineDispatcher, + val bgDispatcher: CoroutineDispatcher, val isEnabled: Boolean, - userHandle: Int, + val handleAllUsers: Boolean, defaultClockProvider: ClockProvider, val fallbackClockId: ClockId = DEFAULT_CLOCK_ID, ) { @@ -50,66 +58,132 @@ open class ClockRegistry( private val availableClocks = mutableMapOf<ClockId, ClockInfo>() private val clockChangeListeners = mutableListOf<ClockChangeListener>() - private val settingObserver = object : ContentObserver(handler) { - override fun onChange(selfChange: Boolean, uris: Collection<Uri>, flags: Int, userId: Int) = - clockChangeListeners.forEach { it.onClockChanged() } - } + private val settingObserver = + object : ContentObserver(null) { + override fun onChange( + selfChange: Boolean, + uris: Collection<Uri>, + flags: Int, + userId: Int + ) { + scope.launch(bgDispatcher) { querySettings() } + } + } - private val pluginListener = object : PluginListener<ClockProviderPlugin> { - override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) = - connectClocks(plugin) + private val pluginListener = + object : PluginListener<ClockProviderPlugin> { + override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) = + connectClocks(plugin) - override fun onPluginDisconnected(plugin: ClockProviderPlugin) = - disconnectClocks(plugin) - } + override fun onPluginDisconnected(plugin: ClockProviderPlugin) = + disconnectClocks(plugin) + } - open var settings: ClockSettings? - get() { - try { - val json = Settings.Secure.getString( - context.contentResolver, - Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE - ) - if (json == null || json.isEmpty()) { - return null - } - return ClockSettings.deserialize(json) - } catch (ex: Exception) { - Log.e(TAG, "Failed to parse clock settings", ex) - return null + private val userSwitchObserver = + object : UserSwitchObserver() { + override fun onUserSwitchComplete(newUserId: Int) { + scope.launch(bgDispatcher) { querySettings() } } } + + // TODO(b/267372164): Migrate to flows + var settings: ClockSettings? = null + get() = field protected set(value) { + if (field != value) { + field = value + scope.launch(mainDispatcher) { onClockChanged() } + } + } + + var isRegistered: Boolean = false + private set + + @OpenForTesting + open fun querySettings() { + assertNotMainThread() + val result = try { - val json = if (value != null) { - value._applied_timestamp = System.currentTimeMillis() - ClockSettings.serialize(value) - } else { - "" - } + val json = + if (handleAllUsers) { + Settings.Secure.getStringForUser( + context.contentResolver, + Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, + ActivityManager.getCurrentUser() + ) + } else { + Settings.Secure.getString( + context.contentResolver, + Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE + ) + } + + ClockSettings.deserialize(json) + } catch (ex: Exception) { + Log.e(TAG, "Failed to parse clock settings", ex) + null + } + settings = result + } + @OpenForTesting + open fun applySettings(value: ClockSettings?) { + assertNotMainThread() + + try { + value?._applied_timestamp = System.currentTimeMillis() + val json = ClockSettings.serialize(value) + + if (handleAllUsers) { + Settings.Secure.putStringForUser( + context.contentResolver, + Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, + json, + ActivityManager.getCurrentUser() + ) + } else { Settings.Secure.putString( context.contentResolver, - Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, json + Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, + json ) - } catch (ex: Exception) { - Log.e(TAG, "Failed to set clock settings", ex) } + } catch (ex: Exception) { + Log.e(TAG, "Failed to set clock settings", ex) } + settings = value + } + + @OpenForTesting + protected open fun assertMainThread() { + Assert.isMainThread() + } - private fun mutateSetting(mutator: (ClockSettings) -> Unit) { - val settings = this.settings ?: ClockSettings() - mutator(settings) - this.settings = settings + @OpenForTesting + protected open fun assertNotMainThread() { + Assert.isNotMainThread() + } + + private fun onClockChanged() { + assertMainThread() + clockChangeListeners.forEach { it.onClockChanged() } + } + + private fun mutateSetting(mutator: (ClockSettings) -> ClockSettings) { + scope.launch(bgDispatcher) { applySettings(mutator(settings ?: ClockSettings())) } } var currentClockId: ClockId get() = settings?.clockId ?: fallbackClockId - set(value) { mutateSetting { it.clockId = value } } + set(value) { + mutateSetting { it.copy(clockId = value) } + } var seedColor: Int? get() = settings?.seedColor - set(value) { mutateSetting { it.seedColor = value } } + set(value) { + mutateSetting { it.copy(seedColor = value) } + } init { connectClocks(defaultClockProvider) @@ -118,22 +192,54 @@ open class ClockRegistry( "$defaultClockProvider did not register clock at $DEFAULT_CLOCK_ID" ) } + } - if (isEnabled) { - pluginManager.addPluginListener( - pluginListener, - ClockProviderPlugin::class.java, - /*allowMultiple=*/ true - ) + fun registerListeners() { + if (!isEnabled || isRegistered) { + return + } + + isRegistered = true + + pluginManager.addPluginListener( + pluginListener, + ClockProviderPlugin::class.java, + /*allowMultiple=*/ true + ) + + scope.launch(bgDispatcher) { querySettings() } + if (handleAllUsers) { context.contentResolver.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE), /*notifyForDescendants=*/ false, settingObserver, - userHandle + UserHandle.USER_ALL + ) + + ActivityManager.getService().registerUserSwitchObserver(userSwitchObserver, TAG) + } else { + context.contentResolver.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE), + /*notifyForDescendants=*/ false, + settingObserver ) } } + fun unregisterListeners() { + if (!isRegistered) { + return + } + + isRegistered = false + + pluginManager.removePluginListener(pluginListener) + context.contentResolver.unregisterContentObserver(settingObserver) + if (handleAllUsers) { + ActivityManager.getService().unregisterUserSwitchObserver(userSwitchObserver) + } + } + private fun connectClocks(provider: ClockProvider) { val currentId = currentClockId for (clock in provider.getClocks()) { @@ -157,7 +263,7 @@ open class ClockRegistry( if (DEBUG) { Log.i(TAG, "Current clock ($currentId) was connected") } - clockChangeListeners.forEach { it.onClockChanged() } + onClockChanged() } } } @@ -172,13 +278,12 @@ open class ClockRegistry( if (currentId == clock.clockId) { Log.w(TAG, "Current clock ($currentId) was disconnected") - clockChangeListeners.forEach { it.onClockChanged() } + onClockChanged() } } } - @OpenForTesting - open fun getClocks(): List<ClockMetadata> { + fun getClocks(): List<ClockMetadata> { if (!isEnabled) { return listOf(availableClocks[DEFAULT_CLOCK_ID]!!.metadata) } @@ -213,16 +318,16 @@ open class ClockRegistry( return createClock(DEFAULT_CLOCK_ID)!! } - private fun createClock(clockId: ClockId): ClockController? { - val settings = this.settings ?: ClockSettings() - if (clockId != settings.clockId) { - settings.clockId = clockId + private fun createClock(targetClockId: ClockId): ClockController? { + var settings = this.settings ?: ClockSettings() + if (targetClockId != settings.clockId) { + settings = settings.copy(clockId = targetClockId) } - return availableClocks[clockId]?.provider?.createClock(settings) + return availableClocks[targetClockId]?.provider?.createClock(settings) } private data class ClockInfo( val metadata: ClockMetadata, - val provider: ClockProvider + val provider: ClockProvider, ) } diff --git a/packages/SystemUI/src/com/android/systemui/util/Assert.java b/packages/SystemUI/customization/src/com/android/systemui/util/Assert.java index e08936cbf75e..e08936cbf75e 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Assert.java +++ b/packages/SystemUI/customization/src/com/android/systemui/util/Assert.java diff --git a/packages/SystemUI/docs/qs-tiles.md b/packages/SystemUI/docs/qs-tiles.md index 4cb765dab741..488f8c728d82 100644 --- a/packages/SystemUI/docs/qs-tiles.md +++ b/packages/SystemUI/docs/qs-tiles.md @@ -301,9 +301,13 @@ This section describes necessary and recommended steps when implementing a Quick * Use only `handleUpdateState` to modify the values of the state to the new ones. This can be done by polling controllers or through the `arg` parameter. * If the controller is not a `CallbackController`, respond to `handleSetListening` by attaching/dettaching from controllers. * Implement `isAvailable` so the tile will not be created when it's not necessary. -4. In `QSFactoryImpl`: - * Inject a `Provider` for the tile created before. - * Add a case to the `switch` with a unique String spec for the chosen tile. +4. Either create a new feature module or find an existing related feature module and add the following binding method: + * ```kotlin + @Binds + @IntoMap + @StringKey(YourNewTile.TILE_SPEC) // A unique word that will map to YourNewTile + fun bindYourNewTile(yourNewTile: YourNewTile): QSTileImpl<*> + ``` 5. In [SystemUI/res/values/config.xml](/packages/SystemUI/res/values/config.xml), modify `quick_settings_tiles_stock` and add the spec defined in the previous step. If necessary, add it also to `quick_settings_tiles_default`. The first one contains a list of all the tiles that SystemUI knows how to create (to show to the user in the customization screen). The second one contains only the default tiles that the user will experience on a fresh boot or after they reset their tiles. 6. In [SystemUI/res/values/tiles_states_strings.xml](/packages/SystemUI/res/values/tiles_states_strings.xml), add a new array for your tile. The name has to be `tile_states_<spec>`. Use a good description to help the translators. 7. In [`SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt), add a new element to the map in `SubtitleArrayMapping` corresponding to the resource created in the previous step. diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt index 1a67691e30bf..22158571bcd6 100644 --- a/packages/SystemUI/ktfmt_includes.txt +++ b/packages/SystemUI/ktfmt_includes.txt @@ -452,12 +452,6 @@ -packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt -packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt -packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt --packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt --packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt --packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt --packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt --packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt --packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt -packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt -packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsController.kt -packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt @@ -743,10 +737,6 @@ -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/ShadeExpansionStateManagerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerOldImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt --packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt --packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt --packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt --packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt index 590015df37aa..1c2f38beb867 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt @@ -45,7 +45,7 @@ interface ClockProvider { /** Initializes and returns the target clock design */ @Deprecated("Use overload with ClockSettings") fun createClock(id: ClockId): ClockController { - return createClock(ClockSettings(id, null, null)) + return createClock(ClockSettings(id, null)) } /** Initializes and returns the target clock design */ @@ -186,16 +186,21 @@ data class ClockMetadata( /** Structure for keeping clock-specific settings */ @Keep data class ClockSettings( - var clockId: ClockId? = null, - var seedColor: Int? = null, - var _applied_timestamp: Long? = null, + val clockId: ClockId? = null, + val seedColor: Int? = null, ) { + var _applied_timestamp: Long? = null + companion object { private val KEY_CLOCK_ID = "clockId" private val KEY_SEED_COLOR = "seedColor" private val KEY_TIMESTAMP = "_applied_timestamp" - fun serialize(setting: ClockSettings): String { + fun serialize(setting: ClockSettings?): String { + if (setting == null) { + return "" + } + return JSONObject() .put(KEY_CLOCK_ID, setting.clockId) .put(KEY_SEED_COLOR, setting.seedColor) @@ -203,13 +208,21 @@ data class ClockSettings( .toString() } - fun deserialize(jsonStr: String): ClockSettings { + fun deserialize(jsonStr: String?): ClockSettings? { + if (jsonStr.isNullOrEmpty()) { + return null + } + val json = JSONObject(jsonStr) - return ClockSettings( - json.getString(KEY_CLOCK_ID), - if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null, - if (!json.isNull(KEY_TIMESTAMP)) json.getLong(KEY_TIMESTAMP) else null - ) + val result = + ClockSettings( + json.getString(KEY_CLOCK_ID), + if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null + ) + if (!json.isNull(KEY_TIMESTAMP)) { + result._applied_timestamp = json.getLong(KEY_TIMESTAMP) + } + return result } } } diff --git a/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml b/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml index fc18132d4dc3..6fe7d39f748a 100644 --- a/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml +++ b/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.systemui.common.ui.view.LaunchableLinearLayout +<com.android.systemui.animation.view.LaunchableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="0dp" android:layout_height="@dimen/qs_security_footer_single_line_height" @@ -63,4 +63,4 @@ android:src="@*android:drawable/ic_chevron_end" android:autoMirrored="true" android:tint="?android:attr/textColorSecondary" /> -</com.android.systemui.common.ui.view.LaunchableLinearLayout>
\ No newline at end of file +</com.android.systemui.animation.view.LaunchableLinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml index fba2c8b188a2..7888e5329cf1 100644 --- a/packages/SystemUI/res-keyguard/values-ca/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml @@ -53,7 +53,7 @@ <string name="kg_wrong_pattern" msgid="5907301342430102842">"Patró incorrecte"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Contrasenya incorrecta"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"El PIN no és correcte"</string> - <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Torna-ho a provar d\'aquí a # segon.}many{Try again in # seconds.}other{Torna-ho a provar d\'aquí a # segons.}}"</string> + <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Torna-ho a provar d\'aquí a # segon.}many{Torna-ho a provar d\'aquí a # segons.}other{Torna-ho a provar d\'aquí a # segons.}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introdueix el PIN de la SIM."</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introdueix el PIN de la SIM de: <xliff:g id="CARRIER">%1$s</xliff:g>."</string> <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desactiva l\'eSIM per utilitzar el dispositiu sense servei mòbil."</string> @@ -68,9 +68,9 @@ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Has escrit la contrasenya <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string> <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"El codi PIN de la SIM no és correcte. Contacta amb l\'operador de telefonia mòbil per desbloquejar el dispositiu."</string> - <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{El codi PIN de la SIM no és correcte. Et queda # intent; si no l\'encertes, contacta amb l\'operador per desbloquejar el dispositiu.}many{Incorrect SIM PIN code, you have # remaining attempts. }other{El codi PIN de la SIM no és correcte. Et queden # intents. }}"</string> + <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{El codi PIN de la SIM no és correcte. Et queda # intent; si no l\'encertes, contacta amb l\'operador per desbloquejar el dispositiu.}many{El codi PIN de la SIM no és correcte. Et queden # intents. }other{El codi PIN de la SIM no és correcte. Et queden # intents. }}"</string> <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"La SIM no es pot fer servir. Contacta amb l\'operador de telefonia mòbil."</string> - <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{El codi PUK de la SIM no és correcte. Et queda # intent; si no l\'encertes, la SIM no es podrà tornar a fer servir.}many{Incorrect SIM PUK code, you have # remaining attempts before SIM becomes permanently unusable.}other{El codi PUK de la SIM no és correcte. Et queden # intents; si no l\'encertes, la SIM no es podrà tornar a fer servir.}}"</string> + <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{El codi PUK de la SIM no és correcte. Et queda # intent; si no l\'encertes, la SIM no es podrà tornar a fer servir.}many{El codi PUK de la SIM no és correcte. Et queden # intents; si no l\'encertes, la SIM no es podrà tornar a fer servir.}other{El codi PUK de la SIM no és correcte. Et queden # intents; si no l\'encertes, la SIM no es podrà tornar a fer servir.}}"</string> <string name="kg_password_pin_failed" msgid="5136259126330604009">"Ha fallat l\'operació del PIN de la SIM"</string> <string name="kg_password_puk_failed" msgid="6778867411556937118">"No s\'ha pogut desbloquejar la SIM amb el codi PUK."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Canvia el mètode d\'introducció"</string> @@ -85,8 +85,8 @@ <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositiu s\'ha bloquejat manualment"</string> <string name="kg_face_not_recognized" msgid="7903950626744419160">"No s\'ha reconegut"</string> <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Desbloqueig facial necessita accés a la càmera"</string> - <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introdueix el PIN de la SIM. Et queda # intent; si no l\'encertes, contacta amb l\'operador per desbloquejar el dispositiu.}many{Enter SIM PIN. You have # remaining attempts.}other{Introdueix el PIN de la SIM. Et queden # intents.}}"</string> - <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queda # intent; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador per obtenir informació.}many{SIM is now disabled. Enter PUK code to continue. You have # remaining attempts before SIM becomes permanently unusable. Contact carrier for details.}other{La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queden # intents; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador per obtenir informació.}}"</string> + <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introdueix el PIN de la SIM. Et queda # intent; si no l\'encertes, contacta amb l\'operador per desbloquejar el dispositiu.}many{Introdueix el PIN de la SIM. Et queden # intents.}other{Introdueix el PIN de la SIM. Et queden # intents.}}"</string> + <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queda # intent; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador per obtenir informació.}many{La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queden # intents; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador per obtenir informació.}other{La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queden # intents; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador per obtenir informació.}}"</string> <string name="clock_title_default" msgid="6342735240617459864">"Predeterminada"</string> <string name="clock_title_bubble" msgid="2204559396790593213">"Bombolla"</string> <string name="clock_title_analog" msgid="8409262532900918273">"Analògica"</string> diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml index 3c794c6f7fe4..d5dba42ef974 100644 --- a/packages/SystemUI/res-keyguard/values-eu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml @@ -84,7 +84,7 @@ <string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administratzaileak blokeatu egin du gailua"</string> <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Eskuz blokeatu da gailua"</string> <string name="kg_face_not_recognized" msgid="7903950626744419160">"Ez da ezagutu"</string> - <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Aurpegi bidezko desblokeoak kamera atzitzeko baimena behar du"</string> + <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Aurpegi bidezko desblokeoak kamera erabiltzeko baimena behar du"</string> <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Idatzi SIMaren PINa. # saiakera geratzen zaizu gailua desblokeatzeko operadorearekin harremanetan jarri behar izan aurretik.}other{Idatzi SIMaren PINa. # saiakera gelditzen zaizkizu.}}"</string> <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{Orain, SIMa desgaituta dago. Aurrera egiteko, idatzi PUK kodea. # saiakera geratzen zaizu SIMa betiko ez-erabilgarri geratu aurretik. Xehetasunak lortzeko, jarri operadorearekin harremanetan.}other{Orain, SIMa desgaituta dago. Aurrera egiteko, idatzi PUK kodea. # saiakera geratzen zaizkizu SIMa betiko ez-erabilgarri geratu aurretik. Xehetasunak lortzeko, jarri operadorearekin harremanetan.}}"</string> <string name="clock_title_default" msgid="6342735240617459864">"Lehenetsia"</string> diff --git a/packages/SystemUI/res/drawable/ic_progress_activity.xml b/packages/SystemUI/res/drawable/ic_progress_activity.xml new file mode 100644 index 000000000000..abf0625d40d5 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_progress_activity.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M24,44Q19.8,44 16.15,42.45Q12.5,40.9 9.8,38.2Q7.1,35.5 5.55,31.85Q4,28.2 4,24Q4,19.8 5.55,16.15Q7.1,12.5 9.8,9.8Q12.5,7.1 16.15,5.55Q19.8,4 24,4Q24.6,4 25.05,4.45Q25.5,4.9 25.5,5.5Q25.5,6.1 25.05,6.55Q24.6,7 24,7Q16.95,7 11.975,11.975Q7,16.95 7,24Q7,31.05 11.975,36.025Q16.95,41 24,41Q31.05,41 36.025,36.025Q41,31.05 41,24Q41,23.4 41.45,22.95Q41.9,22.5 42.5,22.5Q43.1,22.5 43.55,22.95Q44,23.4 44,24Q44,28.2 42.45,31.85Q40.9,35.5 38.2,38.2Q35.5,40.9 31.85,42.45Q28.2,44 24,44Z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_font_scaling.xml b/packages/SystemUI/res/drawable/ic_qs_font_scaling.xml new file mode 100644 index 000000000000..d5b4c9ed5a87 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_font_scaling.xml @@ -0,0 +1,25 @@ +<!-- + Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> +<path + android:pathData="M7,20L7,7L2,7L2,4h13v3h-5v13ZM16,20v-8h-3L13,9h9v3h-3v8Z" + android:fillColor="#041E49"/> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/activity_rear_display_education.xml b/packages/SystemUI/res/layout/activity_rear_display_education.xml index f5fc48c70003..094807e0fad4 100644 --- a/packages/SystemUI/res/layout/activity_rear_display_education.xml +++ b/packages/SystemUI/res/layout/activity_rear_display_education.xml @@ -41,9 +41,10 @@ </androidx.cardview.widget.CardView> <TextView + android:id="@+id/rear_display_title_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/rear_display_fold_bottom_sheet_title" + android:text="@string/rear_display_folded_bottom_sheet_title" android:textAppearance="@style/TextAppearance.Dialog.Title" android:lineSpacingExtra="2sp" android:paddingTop="@dimen/rear_display_title_top_padding" @@ -54,7 +55,7 @@ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/rear_display_bottom_sheet_description" + android:text="@string/rear_display_folded_bottom_sheet_description" android:textAppearance="@style/TextAppearance.Dialog.Body" android:lineSpacingExtra="2sp" android:translationY="-1.24sp" diff --git a/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml b/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml index 6de06f76ebbf..e970bc573b01 100644 --- a/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml +++ b/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml @@ -42,9 +42,10 @@ </androidx.cardview.widget.CardView> <TextView + android:id="@+id/rear_display_title_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/rear_display_unfold_bottom_sheet_title" + android:text="@string/rear_display_unfolded_bottom_sheet_title" android:textAppearance="@style/TextAppearance.Dialog.Title" android:lineSpacingExtra="2sp" android:paddingTop="@dimen/rear_display_title_top_padding" @@ -55,21 +56,11 @@ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/rear_display_bottom_sheet_description" + android:text="@string/rear_display_unfolded_bottom_sheet_description" android:textAppearance="@style/TextAppearance.Dialog.Body" android:lineSpacingExtra="2sp" android:translationY="-1.24sp" android:gravity="center_horizontal|top" /> - <TextView - android:id="@+id/rear_display_warning_text_view" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/rear_display_bottom_sheet_warning" - android:textAppearance="@style/TextAppearance.Dialog.Body" - android:lineSpacingExtra="2sp" - android:gravity="center_horizontal|top" - /> - </LinearLayout> diff --git a/packages/SystemUI/res/layout/chipbar.xml b/packages/SystemUI/res/layout/chipbar.xml index 8cf4f4de27da..0ff944c2becf 100644 --- a/packages/SystemUI/res/layout/chipbar.xml +++ b/packages/SystemUI/res/layout/chipbar.xml @@ -60,14 +60,13 @@ /> <!-- At most one of [loading, failure_icon, undo] will be visible at a time. --> - <ProgressBar + <ImageView android:id="@+id/loading" - android:indeterminate="true" android:layout_width="@dimen/media_ttt_status_icon_size" android:layout_height="@dimen/media_ttt_status_icon_size" android:layout_marginStart="@dimen/media_ttt_last_item_start_margin" - android:indeterminateTint="?androidprv:attr/colorAccentPrimaryVariant" - style="?android:attr/progressBarStyleSmall" + android:src="@drawable/ic_progress_activity" + android:tint="?androidprv:attr/colorAccentPrimaryVariant" android:alpha="0.0" /> diff --git a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml index 446bb0122630..fb78b49dfcc2 100644 --- a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml +++ b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml @@ -20,7 +20,7 @@ android:layout_width="wrap_content" android:paddingVertical="@dimen/dream_overlay_complication_home_controls_padding"> - <com.android.systemui.common.ui.view.LaunchableImageView + <com.android.systemui.animation.view.LaunchableImageView android:id="@+id/home_controls_chip" android:layout_height="@dimen/keyguard_affordance_fixed_height" android:layout_width="@dimen/keyguard_affordance_fixed_width" diff --git a/packages/SystemUI/res/layout/font_scaling_dialog.xml b/packages/SystemUI/res/layout/font_scaling_dialog.xml new file mode 100644 index 000000000000..27c1e9d03df9 --- /dev/null +++ b/packages/SystemUI/res/layout/font_scaling_dialog.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<com.android.systemui.common.ui.view.SeekBarWithIconButtonsView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/font_scaling_slider" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center" + app:max="6" + app:progress="0" + app:iconStartContentDescription="@string/font_scaling_smaller" + app:iconEndContentDescription="@string/font_scaling_larger"/>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index 3f955154c875..2871cdf6f9f6 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -59,7 +59,7 @@ </LinearLayout> - <com.android.systemui.common.ui.view.LaunchableImageView + <com.android.systemui.animation.view.LaunchableImageView android:id="@+id/start_button" android:layout_height="@dimen/keyguard_affordance_fixed_height" android:layout_width="@dimen/keyguard_affordance_fixed_width" @@ -72,7 +72,7 @@ android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset" android:visibility="gone" /> - <com.android.systemui.common.ui.view.LaunchableImageView + <com.android.systemui.animation.view.LaunchableImageView android:id="@+id/end_button" android:layout_height="@dimen/keyguard_affordance_fixed_height" android:layout_width="@dimen/keyguard_affordance_fixed_width" diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml index f2e114b511bc..9d914197c05a 100644 --- a/packages/SystemUI/res/layout/media_session_view.xml +++ b/packages/SystemUI/res/layout/media_session_view.xml @@ -106,7 +106,7 @@ app:layout_constrainedWidth="true" app:layout_constraintWidth_min="@dimen/min_clickable_item_size" app:layout_constraintHeight_min="@dimen/min_clickable_item_size"> - <com.android.systemui.common.ui.view.LaunchableLinearLayout + <com.android.systemui.animation.view.LaunchableLinearLayout android:id="@+id/media_seamless_button" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -135,7 +135,7 @@ android:textDirection="locale" android:textSize="12sp" android:lineHeight="16sp" /> - </com.android.systemui.common.ui.view.LaunchableLinearLayout> + </com.android.systemui.animation.view.LaunchableLinearLayout> </LinearLayout> <!-- Song name --> diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_call_chip.xml index 18d231c5d32f..238fc8438331 100644 --- a/packages/SystemUI/res/layout/ongoing_call_chip.xml +++ b/packages/SystemUI/res/layout/ongoing_call_chip.xml @@ -23,7 +23,7 @@ android:layout_gravity="center_vertical|start" android:layout_marginStart="5dp" > - <com.android.systemui.common.ui.view.LaunchableLinearLayout + <com.android.systemui.animation.view.LaunchableLinearLayout android:id="@+id/ongoing_call_chip_background" android:layout_width="wrap_content" android:layout_height="@dimen/ongoing_appops_chip_height" @@ -55,5 +55,5 @@ android:textColor="?android:attr/colorPrimary" /> - </com.android.systemui.common.ui.view.LaunchableLinearLayout> + </com.android.systemui.animation.view.LaunchableLinearLayout> </FrameLayout> diff --git a/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml b/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml new file mode 100644 index 000000000000..52d1d4fa9bf9 --- /dev/null +++ b/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/seekbar_frame" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipChildren="false" + android:gravity="center_vertical" + android:orientation="horizontal" + tools:parentTag="android.widget.LinearLayout"> + + <FrameLayout + android:id="@+id/icon_start_frame" + android:layout_width="@dimen/min_clickable_item_size" + android:layout_height="@dimen/min_clickable_item_size" + android:clipChildren="false" + android:focusable="true" > + <ImageView + android:id="@+id/icon_start" + android:layout_width="@dimen/seekbar_icon_size" + android:layout_height="@dimen/seekbar_icon_size" + android:layout_gravity="center" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:adjustViewBounds="true" + android:focusable="false" + android:src="@drawable/ic_remove" + android:tint="?android:attr/textColorPrimary" + android:tintMode="src_in" /> + </FrameLayout> + + <SeekBar + android:id="@+id/seekbar" + style="@android:style/Widget.Material.SeekBar.Discrete" + android:layout_width="0dp" + android:layout_height="48dp" + android:layout_gravity="center_vertical" + android:layout_weight="1" /> + + <FrameLayout + android:id="@+id/icon_end_frame" + android:layout_width="@dimen/min_clickable_item_size" + android:layout_height="@dimen/min_clickable_item_size" + android:clipChildren="false" + android:focusable="true" > + <ImageView + android:id="@+id/icon_end" + android:layout_width="@dimen/seekbar_icon_size" + android:layout_height="@dimen/seekbar_icon_size" + android:layout_gravity="center" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:adjustViewBounds="true" + android:focusable="false" + android:src="@drawable/ic_add" + android:tint="?android:attr/textColorPrimary" + android:tintMode="src_in" /> + </FrameLayout> + +</merge> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 782187a1f049..65c2417102b4 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Iets is fout. Probeer weer."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Laai tans"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Saai jou media uit"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Saai tans <xliff:g id="APP_LABEL">%1$s</xliff:g> uit"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrole is nie beskikbaar nie"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 57e160ef8f53..d2d7e64b34ae 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"የሆነ ችግር ተፈጥሯል። እንደገና ይሞክሩ።"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"በመጫን ላይ"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ጡባዊ"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"የእርስዎን ሚዲያ cast በማድረግ ላይ"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"<xliff:g id="APP_LABEL">%1$s</xliff:g>ን Cast በማድረግ ላይ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"መቆጣጠሪያ አይገኝም"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index d638d524cf3b..66279d3c942f 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"الحد السفلى <xliff:g id="PERCENT">%1$d</xliff:g> في المئة"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"الحد الأيسر <xliff:g id="PERCENT">%1$d</xliff:g> في المئة"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"الحد الأيمن <xliff:g id="PERCENT">%1$d</xliff:g> في المئة"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"تم حفظ لقطة الشاشة في \"<xliff:g id="APP">%1$s</xliff:g>\" في الملف الشخصي للعمل."</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"الملفات"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"رصَد تطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\" لقطة الشاشة هذه."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"رصَد تطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\" والتطبيقات المفتوحة الأخرى لقطة الشاشة هذه."</string> <string name="screenrecord_name" msgid="2596401223859996572">"مسجّل الشاشة"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"جارٍ معالجة تسجيل الشاشة"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"إشعار مستمر لجلسة تسجيل شاشة"</string> @@ -794,11 +791,11 @@ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"تبديل"</string> <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"انقر لفتح ميزات تسهيل الاستخدام. يمكنك تخصيص هذا الزر أو استبداله من الإعدادات.\n\n"<annotation id="link">"عرض الإعدادات"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"يمكنك نقل الزر إلى الحافة لإخفائه مؤقتًا."</string> - <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"نقل إلى أعلى يمين الشاشة"</string> - <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"نقل إلى أعلى يسار الشاشة"</string> - <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"نقل إلى أسفل يمين الشاشة"</string> - <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"نقل إلى أسفل يسار الشاشة"</string> - <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"نقله إلى الحافة وإخفاؤه"</string> + <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"النقل إلى أعلى يمين الشاشة"</string> + <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"النقل إلى أعلى يسار الشاشة"</string> + <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"النقل إلى أسفل يمين الشاشة"</string> + <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"النقل إلى أسفل يسار الشاشة"</string> + <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"النقل إلى الحافة والإخفاء"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"نقله إلى خارج الحافة وإظهاره"</string> <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"إيقاف/تفعيل"</string> <string name="quick_controls_title" msgid="6839108006171302273">"التحكم بالجهاز"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"حدث خطأ. يُرجى إعادة المحاولة."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"جارٍ التحميل"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"جهاز لوحي"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string> <string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"عنصر التحكّم غير متوفّر"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 01148d549478..688025bcb652 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"কিবা ভুল হ’ল। পুনৰ চেষ্টা কৰক।"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"ল’ড হৈ আছে"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"টেবলেট"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্টো পৰীক্ষা কৰক"</string> <string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"নিয়ন্ত্ৰণটো উপলব্ধ নহয়"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index dc8e7daba317..77bf65bd5819 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -180,7 +180,7 @@ <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> üzərindən qoşuldu."</string> <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> cihazına qoşulub."</string> <string name="accessibility_not_connected" msgid="4061305616351042142">"Qoşulu deyil."</string> - <string name="data_connection_roaming" msgid="375650836665414797">"Rominq"</string> + <string name="data_connection_roaming" msgid="375650836665414797">"Rouminq"</string> <string name="cell_data_off" msgid="4886198950247099526">"Deaktiv"</string> <string name="accessibility_airplane_mode" msgid="1899529214045998505">"Uçuş rejimi"</string> <string name="accessibility_vpn_on" msgid="8037549696057288731">"VPN aktivdir."</string> @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Xəta oldu. Yenə cəhd edin."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Yüklənir"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"planşet"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Nəzarət əlçatan deyil"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 5b11dbc9bb3f..78812ae855af 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Došlo je do greške. Probajte ponovo."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Učitava se"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 22b1c24c0c29..b539e992bdf1 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ніжняя граніца: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Левая граніца: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Правая граніца: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Захавана ў праграму \"<xliff:g id="APP">%1$s</xliff:g>\" (у працоўным профілі)"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Файлы"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"Праграма \"<xliff:g id="APPNAME">%1$s</xliff:g>\" выявіла гэты здымак экрана."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> і іншыя адкрытыя праграмы выявілі гэты здымак экрана."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Запіс экрана"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Апрацоўваецца запіс экрана"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Бягучае апавяшчэнне для сеанса запісу экрана"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Нешта пайшло не так. Паўтарыце спробу."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Ідзе загрузка"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"планшэт"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Кіраванне недаступнае"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 1adb80ba8133..a45ca4c44a0f 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Долна граница: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Лява граница: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Дясна граница: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Запазена в(ъв) <xliff:g id="APP">%1$s</xliff:g> в служебния потребителски профил"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> установи заснемането на тази екранна снимка."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> и други отворени приложения установиха заснемането на тази екранна снимка."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Запис на екрана"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Записът на екрана се обработва"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущо известие за сесия за записване на екрана"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Нещо се обърка. Опитайте отново."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Зарежда се"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"таблет"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е налице"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index bdda1a37d129..08b7ca4ce052 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"কোনও সমস্যা হয়েছে। আবার চেষ্টা করুন।"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"লোড করা হচ্ছে"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ট্যাবলেট"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string> <string name="controls_error_removed" msgid="6675638069846014366">"খুঁজে পাওয়া যায়নি"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"কন্ট্রোল উপলভ্য নেই"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index fe947dfcc261..e7a6006f837a 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Nešto nije uredu. Pokušajte ponovo."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Učitavanje"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Emitiranje medijskih sadržaja"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Emitiranje aplikacije <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index b1e0ddc21eb0..109aeb704b14 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Marge inferior <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Marge esquerre <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Marge dret <xliff:g id="PERCENT">%1$d</xliff:g> per cent"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"S\'ha desat al perfil de treball de <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fitxers"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ha detectat aquesta captura de pantalla."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> i altres aplicacions obertes han detectat aquesta captura de pantalla."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Gravació de pantalla"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processant gravació de pantalla"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificació en curs d\'una sessió de gravació de la pantalla"</string> @@ -221,7 +218,7 @@ <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensors desactivats"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Esborra totes les notificacions."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> - <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# notificació més a l\'interior.}many{# more notifications inside.}other{# notificacions més a l\'interior.}}"</string> + <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# notificació més a l\'interior.}many{# notificacions més a l\'interior.}other{# notificacions més a l\'interior.}}"</string> <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"La pantalla està bloquejada en orientació horitzontal."</string> <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"La pantalla està bloquejada en orientació vertical."</string> <string name="dessert_case" msgid="9104973640704357717">"Capsa de postres"</string> @@ -269,7 +266,7 @@ <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Punt d\'accés Wi-Fi"</string> <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"S\'està activant…"</string> <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Estalvi dades activat"</string> - <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositiu}many{# devices}other{# dispositius}}"</string> + <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositiu}many{# dispositius}other{# dispositius}}"</string> <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Llanterna"</string> <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Càmera en ús"</string> <string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Dades mòbils"</string> @@ -370,7 +367,7 @@ <string name="guest_notification_session_active" msgid="5567273684713471450">"Estàs en mode de convidat"</string> <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"En afegir un usuari nou, se sortirà del mode de convidat i se suprimiran totes les aplicacions i dades de la sessió de convidat actual."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"S\'ha assolit el límit d\'usuaris"</string> - <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Només es pot crear 1 usuari.}many{You can add up to # users.}other{Pots afegir fins a # usuaris.}}"</string> + <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Només es pot crear 1 usuari.}many{Pots afegir fins a # usuaris.}other{Pots afegir fins a # usuaris.}}"</string> <string name="user_remove_user_title" msgid="9124124694835811874">"Vols suprimir l\'usuari?"</string> <string name="user_remove_user_message" msgid="6702834122128031833">"Totes les aplicacions i les dades d\'aquest usuari se suprimiran."</string> <string name="user_remove_user_remove" msgid="8387386066949061256">"Suprimeix"</string> @@ -573,8 +570,8 @@ <string name="notification_menu_snooze_action" msgid="5415729610393475019">"Recorda-m\'ho"</string> <string name="snooze_undo" msgid="2738844148845992103">"Desfés"</string> <string name="snoozed_for_time" msgid="7586689374860469469">"S\'ha posposat <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string> - <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# hores}many{# hours}other{# hores}}"</string> - <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minut}many{# minutes}other{# minuts}}"</string> + <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# hores}many{# hores}other{# hores}}"</string> + <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minut}many{# minuts}other{# minuts}}"</string> <string name="battery_detail_switch_title" msgid="6940976502957380405">"Estalvi de bateria"</string> <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botó <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Inici"</string> @@ -803,7 +800,7 @@ <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"commuta"</string> <string name="quick_controls_title" msgid="6839108006171302273">"Controls de dispositius"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Selecciona l\'aplicació per afegir controls"</string> - <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{S\'ha afegit # control.}many{# controls added.}other{S\'han afegit # controls.}}"</string> + <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{S\'ha afegit # control.}many{S\'han afegit # controls.}other{S\'han afegit # controls.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Suprimit"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vols afegir <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="controls_panel_authorization" msgid="4540047176861801815">"En afegir <xliff:g id="APPNAME">%s</xliff:g>, podrà afegir controls i contingut en aquest tauler. En algunes aplicacions, pots triar quins controls es mostren aquí."</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"S\'ha produït un error. Torna-ho a provar."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"S\'està carregant"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tauleta"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string> <string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no està disponible"</string> @@ -972,7 +973,7 @@ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Afegeix la icona"</string> <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No afegeixis la icona"</string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecciona un usuari"</string> - <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# aplicació està activa}many{# apps are active}other{# aplicacions estan actives}}"</string> + <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# aplicació està activa}many{# aplicacions estan actives}other{# aplicacions estan actives}}"</string> <string name="fgs_dot_content_description" msgid="2865071539464777240">"Informació nova"</string> <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicacions actives"</string> <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Aquestes aplicacions estan actives i executant-se, fins i tot quan no les utilitzes. Això en millora la funcionalitat, però també pot afectar la durada de la bateria."</string> @@ -1002,7 +1003,7 @@ <string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"La càmera està desactivada"</string> <string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"El micròfon està desactivat"</string> <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Càmera i micròfon desactivats"</string> - <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificació}many{# notifications}other{# notificacions}}"</string> + <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificació}many{# notificacions}other{# notificacions}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> <string name="note_task_button_label" msgid="8718616095800343136">"Presa de notes"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"S\'està emetent"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index e0da11030263..de48119e7aaa 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Dolní okraj <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Levý okraj <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Pravý okraj <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Uloženo v aplikaci <xliff:g id="APP">%1$s</xliff:g> v pracovním profilu"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Soubory"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"Aplikace <xliff:g id="APPNAME">%1$s</xliff:g> objevila tento snímek obrazovky."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> a ostatní otevřené aplikace objevily tento snímek obrazovky."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Záznam obrazovky se zpracovává"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Trvalé oznámení o relaci nahrávání"</string> @@ -865,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Došlo k chybě. Zkuste to znovu."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Načítání"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Odesílání médií"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Odesílání aplikace <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládání není k dispozici"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index fa9b96acbf1e..73ec8f55589c 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Noget gik galt. Prøv igen."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Indlæser"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Styringselement ikke tilgængeligt"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 9521e71a6274..c3fb287e1cc2 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Unterer Rand <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Linker Rand <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Rechter Rand <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"In <xliff:g id="APP">%1$s</xliff:g> im Arbeitsprofil gespeichert"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Dateien"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> hat diesen Screenshot erkannt."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> und andere geöffnete Apps haben diesen Screenshot erkannt."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Bildschirmaufzeichnung"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Bildschirmaufzeichnung…"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Fortlaufende Benachrichtigung für eine Bildschirmaufzeichnung"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Ein Fehler ist aufgetreten. Versuch es noch einmal."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Wird geladen"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"Tablet"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Steuerelement nicht verfügbar"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 9f6a1c3cfaa8..dacd2f07d588 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Παρουσιάστηκε κάποιο πρόβλημα. Δοκιμάστε ξανά."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Φόρτωση"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Μετάδοση των μέσων σας"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Μετάδοση <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Μη διαθέσιμο στοιχείο ελέγχου"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index c11b6c4a602f..5f6a481b3a86 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Casting your media"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Casting <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 9b60f22389a5..bd3fa831c84a 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Casting your media"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Casting <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index c11b6c4a602f..5f6a481b3a86 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Casting your media"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Casting <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index c11b6c4a602f..5f6a481b3a86 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Casting your media"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Casting <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index cb95bb02de17..93d48ef56dd8 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Loading"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Casting your media"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Casting <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 7fd8a6ffb7b4..2e179de5b4d4 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Se produjo un error. Vuelve a intentarlo."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Cargando"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 48e3ba9fabf4..2d8f0981fcd6 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"<xliff:g id="PERCENT">%1$d</xliff:g> por ciento del límite inferior"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"<xliff:g id="PERCENT">%1$d</xliff:g> por ciento del límite izquierdo"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"<xliff:g id="PERCENT">%1$d</xliff:g> por ciento del límite derecho"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Se ha guardado en el perfil de trabajo de <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Archivos"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ha detectado esta captura de pantalla."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> y otras aplicaciones abiertas han detectado esta captura de pantalla."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Grabación de pantalla"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación de pantalla"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación continua de una sesión de grabación de la pantalla"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Se ha producido un error. Inténtalo de nuevo."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Cargando"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string> <string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control no disponible"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 6bc736fdd07f..a983a7ab6e25 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Alapiir: <xliff:g id="PERCENT">%1$d</xliff:g> protsenti"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Vasak piir: <xliff:g id="PERCENT">%1$d</xliff:g> protsenti"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Parem piir: <xliff:g id="PERCENT">%1$d</xliff:g> protsenti"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Salvestati tööprofiilil rakendusse <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> tuvastas selle ekraanipildi."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ja muud avatud rakendused tuvastasid selle ekraanipildi."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Ekraanisalvesti"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Midagi läks valesti. Proovige uuesti."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Laadimine"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tahvelarvuti"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Juhtelement pole saadaval"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 4b1931bd54c1..2cd0cedb1eae 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -32,13 +32,13 @@ <string name="battery_saver_start_action" msgid="8353766979886287140">"Aktibatu"</string> <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Ez, eskerrik asko"</string> <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Biratu pantaila automatikoki"</string> - <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> atzitzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?"</string> + <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> erabiltzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?"</string> <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> erabiltzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?\nAplikazioak ez du grabatzeko baimenik, baina baliteke USB bidezko gailu horren bidez audioa grabatzea."</string> - <string name="usb_audio_device_permission_prompt_title" msgid="4221351137250093451">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> atzitzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?"</string> + <string name="usb_audio_device_permission_prompt_title" msgid="4221351137250093451">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> erabiltzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?"</string> <string name="usb_audio_device_confirm_prompt_title" msgid="8828406516732985696">"<xliff:g id="APPLICATION">%1$s</xliff:g> ireki nahi duzu <xliff:g id="USB_DEVICE">%2$s</xliff:g> kudeatzeko?"</string> <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"Aplikazioak ez du grabatzeko baimenik, baina baliteke USB bidezko gailu honen bidez audioa grabatzea. <xliff:g id="APPLICATION">%1$s</xliff:g> gailu honekin erabiliz gero, baliteke deiak, jakinarazpenak eta alarmak ez entzutea."</string> <string name="usb_audio_device_prompt" msgid="7944987408206252949">"<xliff:g id="APPLICATION">%1$s</xliff:g> gailu honekin erabiliz gero, baliteke deiak, jakinarazpenak eta alarmak ez entzutea."</string> - <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> atzitzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?"</string> + <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> erabiltzeko baimena eman nahi diozu <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioari?"</string> <string name="usb_device_confirm_prompt" msgid="4091711472439910809">"<xliff:g id="APPLICATION">%1$s</xliff:g> ireki nahi duzu <xliff:g id="USB_DEVICE">%2$s</xliff:g> kudeatzeko?"</string> <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"<xliff:g id="APPLICATION">%1$s</xliff:g> ireki nahi duzu <xliff:g id="USB_DEVICE">%2$s</xliff:g> erabiltzeko?\nAplikazioak ez du grabatzeko baimenik, baina baliteke audioa grabatzea USB bidezko gailu horren bidez."</string> <string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"<xliff:g id="APPLICATION">%1$s</xliff:g> ireki nahi duzu <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> kudeatzeko?"</string> @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Beheko ertza: ehuneko <xliff:g id="PERCENT">%1$d</xliff:g>"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Ezkerreko ertza: ehuneko <xliff:g id="PERCENT">%1$d</xliff:g>"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Eskuineko ertza: ehuneko <xliff:g id="PERCENT">%1$d</xliff:g>"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Laneko profilaren <xliff:g id="APP">%1$s</xliff:g> aplikazioan gorde da"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fitxategiak"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioak pantaila-argazkia hauteman du."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioak eta irekitako beste aplikazio batzuek pantaila-argazkia hauteman dute."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Pantaila-grabagailua"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pantaila-grabaketa prozesatzen"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Pantailaren grabaketa-saioaren jakinarazpen jarraitua"</string> @@ -303,9 +300,9 @@ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Gailuaren mikrofonoa desblokeatu nahi duzu?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Gailuaren kamera desblokeatu nahi duzu?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Gailuaren kamera eta mikrofonoa desblokeatu nahi dituzu?"</string> - <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Mikrofonoa atzitzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dute."</string> - <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kamera atzitzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dute."</string> - <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kamera edo mikrofonoa atzitzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dituzte."</string> + <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Mikrofonoa erabiltzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dute."</string> + <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Kamera erabiltzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dute."</string> + <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Kamera edo mikrofonoa erabiltzeko baimena duten aplikazio eta zerbitzu guztiek erabili ahalko dituzte."</string> <string name="sensor_privacy_start_use_mic_blocked_dialog_title" msgid="2640140287496469689">"Blokeatuta dago mikrofonoa"</string> <string name="sensor_privacy_start_use_camera_blocked_dialog_title" msgid="7398084286822440384">"Blokeatuta dago kamera"</string> <string name="sensor_privacy_start_use_mic_camera_blocked_dialog_title" msgid="195236134743281973">"Blokeatuta daude mikrofonoa eta kamera"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Arazoren bat izan da. Saiatu berriro."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Kargatzen"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tableta"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Ez dago erabilgarri kontrolatzeko aukera"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index df98a7e41d6d..328515001400 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"مرز پایین <xliff:g id="PERCENT">%1$d</xliff:g> درصد"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"مرز سمت چپ <xliff:g id="PERCENT">%1$d</xliff:g> درصد"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"مرز سمت راست <xliff:g id="PERCENT">%1$d</xliff:g> درصد"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"در برنامه <xliff:g id="APP">%1$s</xliff:g> در نمایه کاری ذخیره شد"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> این نماگرفت را تشخیص داد."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> و سایر برنامههای باز این نماگرفت را تشخیص دادند."</string> <string name="screenrecord_name" msgid="2596401223859996572">"ضبطکننده صفحهنمایش"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"درحال پردازش ضبط صفحهنمایش"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"اعلان درحال انجام برای جلسه ضبط صفحهنمایش"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"مشکلی پیش آمد. دوباره امتحان کنید."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"درحال بار کردن"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"رایانه لوحی"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string> <string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"کنترل دردسترس نیست"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index c93c3fae0a57..70af7abeef6e 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Alareuna <xliff:g id="PERCENT">%1$d</xliff:g> prosenttia"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Vasen reuna <xliff:g id="PERCENT">%1$d</xliff:g> prosenttia"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Oikea reuna <xliff:g id="PERCENT">%1$d</xliff:g> prosenttia"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Tallennettu työprofiiliin tässä sovelluksessa: <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> havaitsi tämän kuvakaappauksen."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ja jotkin muut sovellukset havaitsivat tämän kuvakaappauksen."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Näytön tallentaja"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Näytön tallennusta käsitellään"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Pysyvä ilmoitus näytön tallentamisesta"</string> @@ -865,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Jotain meni pieleen. Yritä uudelleen."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Latautuminen"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tabletti"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Striimataan mediaa"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Striimataan <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Ohjain ei ole käytettävissä"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index f1e5fbc1bb4e..e42f24bbe5c5 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Limite inférieure : <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Limite gauche : <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Limite droite : <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Enregistré dans <xliff:g id="APP">%1$s</xliff:g> dans le profil professionnel"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fichiers"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> a détecté cette capture d\'écran."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> et d\'autres applications ouvertes ont détecté cette capture d\'écran."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Trait. de l\'enregist. d\'écran…"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement d\'écran"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Une erreur s\'est produite. Réessayez."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Chargement en cours…"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablette"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"La commande n\'est pas accessible"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index a667728c05b2..371396aa4463 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Limite inférieure : <xliff:g id="PERCENT">%1$d</xliff:g> pour cent"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Limite gauche : <xliff:g id="PERCENT">%1$d</xliff:g> pour cent"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Limite droite : <xliff:g id="PERCENT">%1$d</xliff:g> pour cent"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Enregistré dans <xliff:g id="APP">%1$s</xliff:g>, dans le profil professionnel"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fichiers"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> a détecté cette capture d\'écran."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> et d\'autres applis ouvertes ont détecté cette capture d\'écran."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Enregistrement de l\'écran…"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement de l\'écran"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Un problème est survenu. Réessayez."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Chargement…"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablette"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Commande indisponible"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 260be9bb652c..9bea0ca9d822 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Bordo inferior: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Bordo esquerdo: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Bordo dereito: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Captura de pantalla gardada na aplicación <xliff:g id="APP">%1$s</xliff:g> do perfil de traballo"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Ficheiros"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> detectou esta captura de pantalla."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> e outras aplicacións abertas detectaron esta captura de pantalla."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Gravadora da pantalla"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando gravación pantalla"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación en curso sobre unha sesión de gravación de pantalla"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Produciuse un erro. Téntao de novo."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Cargando"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tableta"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"O control non está dispoñible"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 86b4bc588d39..fa55ea656618 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"નીચેની સીમા <xliff:g id="PERCENT">%1$d</xliff:g> ટકા"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ડાબી બાજુની સીમા <xliff:g id="PERCENT">%1$d</xliff:g> ટકા"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"જમણી બાજુની સીમા <xliff:g id="PERCENT">%1$d</xliff:g> ટકા"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"ઑફિસની પ્રોફાઇલમાં <xliff:g id="APP">%1$s</xliff:g>માં સાચવવામાં આવ્યો"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ફાઇલો"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> દ્વારા આ સ્ક્રીનશૉટ લેવાયાની ભાળ મેળવવામાં આવી."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> અને કામ કરતી અન્ય ઍપ દ્વારા આ સ્ક્રીનશૉટ લેવાયાની ભાળ મેળવવામાં આવી."</string> <string name="screenrecord_name" msgid="2596401223859996572">"સ્ક્રીન રેકોર્ડર"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"સ્ક્રીન રેકૉર્ડિંગ ચાલુ છે"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"સ્ક્રીન રેકોર્ડિંગ સત્ર માટે ચાલુ નોટિફિકેશન"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"કંઈક ખોટું થયું. ફરી પ્રયાસ કરો."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"લોડ થઈ રહ્યું છે"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ટૅબ્લેટ"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string> <string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"નિયંત્રણ ઉપલબ્ધ નથી"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 649c783afdb3..c7b9fecd10f9 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"निचले किनारे से <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"बाएं किनारे से <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"दाएं किनारे से <xliff:g id="PERCENT">%1$d</xliff:g> प्रतिशत"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"वर्क प्रोफ़ाइल में मौजूद <xliff:g id="APP">%1$s</xliff:g> में सेव किया गया है"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> को इस स्क्रीनशॉट का पता चला है."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> और खुले हुए अन्य ऐप्लिकेशन को इस स्क्रीनशॉट का पता चला है."</string> <string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रिकॉर्डर"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रिकॉर्डिंग को प्रोसेस किया जा रहा है"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रिकॉर्ड सेशन के लिए जारी सूचना"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"कोई गड़बड़ी हुई. फिर से कोशिश करें."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"लोड हो रहा है"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"टैबलेट"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string> <string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं है"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"कंट्रोल मौजूद नहीं है"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 53ad4b8923a6..72bdbce2d6dd 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Nešto nije u redu. Pokušajte ponovo."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Učitavanje"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Emitiranje medijskih sadržaja"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Emitiranje aplikacije <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 69656ed21d66..0ad27c4af7b9 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Hiba történt. Próbálkozzon újra."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Betöltés…"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"táblagép"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"A médiatartalom átküldése folyamatban van"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"<xliff:g id="APP_LABEL">%1$s</xliff:g> átküldése"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Nem hozzáférhető vezérlő"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index d4c13995299a..ff8f19af524b 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ներքևի սահմանագիծը՝ <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Ձախ կողմի սահմանագիծը՝ <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Աջ կողմի սահմանագիծը՝ <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Սքրինշոթը պահվեց <xliff:g id="APP">%1$s</xliff:g>-ի աշխատանքային պրոֆիլում"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Ֆայլեր"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> հավելվածը հայտնաբերել է այս սքրինշոթը։"</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g>-ն ու բացված այլ հավելվածներ հայտնաբերել են այս սքրինշոթը։"</string> <string name="screenrecord_name" msgid="2596401223859996572">"Էկրանի տեսագրիչ"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Էկրանի տեսագրության մշակում"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Էկրանի տեսագրման աշխատաշրջանի ընթացիկ ծանուցում"</string> @@ -865,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Սխալ առաջացավ։ Նորից փորձեք։"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Բեռնվում է"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"պլանշետ"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Մեդիա բովանդակության հեռարձակում"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"<xliff:g id="APP_LABEL">%1$s</xliff:g> հավելվածի հեռարձակում"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Կառավարման տարրը հասանելի չէ"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index dca95657f864..12495c164d2d 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Terjadi error. Coba lagi."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Memuat"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol tidak tersedia"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index ad94cdcc897a..87b8a735ccc3 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Neðri mörk <xliff:g id="PERCENT">%1$d</xliff:g> prósent"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Vinstri mörk <xliff:g id="PERCENT">%1$d</xliff:g> prósent"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Hægri mörk <xliff:g id="PERCENT">%1$d</xliff:g> prósent"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Vistað á vinnusniði í <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Skrár"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> greindi skjámyndina."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> og önnur opin forrit greindu skjámyndina."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Skjáupptaka"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Vinnur úr skjáupptöku"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Áframhaldandi tilkynning fyrir skjáupptökulotu"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Eitthvað fór úrskeiðis. Reyndu aftur."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Hleður"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"spjaldtölva"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Stýring er ekki tiltæk"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 389522f5d01d..bc89cbb37b2d 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Si è verificato un errore. Riprova."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Caricamento in corso…"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Trasmissione di contenuti multimediali"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Trasmissione di <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Il controllo non è disponibile"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 95871fc6e3e5..863312774142 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"<xliff:g id="PERCENT">%1$d</xliff:g> אחוז מהשוליים התחתונים"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"<xliff:g id="PERCENT">%1$d</xliff:g> אחוז מהשוליים השמאליים"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"<xliff:g id="PERCENT">%1$d</xliff:g> אחוז מהשוליים הימניים"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"נשמר באפליקציה <xliff:g id="APP">%1$s</xliff:g> בתוך פרופיל העבודה"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"קבצים"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"האפליקציה <xliff:g id="APPNAME">%1$s</xliff:g> זיהתה את צילום המסך הזה."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"האפליקציה <xliff:g id="APPNAME">%1$s</xliff:g> ואפליקציות פתוחות נוספות זיהו את צילום המסך הזה."</string> <string name="screenrecord_name" msgid="2596401223859996572">"מקליט המסך"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"מתבצע עיבוד של הקלטת מסך"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"התראה מתמשכת לסשן הקלטת מסך"</string> @@ -865,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"משהו השתבש. יש לנסות שוב."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"בטעינה"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"טאבלט"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"העברה (cast) של מדיה"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"מתבצעת העברה (cast) של <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string> <string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"הפקד לא זמין"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 92e2c78204f8..9aef2a99adbf 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"エラーが発生しました。もう一度お試しください。"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"読み込んでいます"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"タブレット"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string> <string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"コントロールを使用できません"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 3d8acb3bd34d..62efabe9f9f6 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"რაღაც შეცდომა მოხდა. ცადეთ ხელახლა."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"იტვირთება"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ტაბლეტი"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"მედიის ტრანსლირება"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"მიმდინარეობს <xliff:g id="APP_LABEL">%1$s</xliff:g>-ის ტრანსლირება"</string> <string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ვერ მოიძებნა"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"კონტროლი მიუწვდომელია"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 0f9dc956db51..56d8b91b17de 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Бірдеңе дұрыс болмады. Қайталап көріңіз."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Жүктеліп жатыр"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"планшет"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Басқару виджеті қолжетімсіз"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 9f80e336ec47..3a04488f0405 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"បន្ទាត់បែងចែកខាងក្រោម <xliff:g id="PERCENT">%1$d</xliff:g> ភាគរយ"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"បន្ទាត់បែងចែកខាងឆ្វេង <xliff:g id="PERCENT">%1$d</xliff:g> ភាគរយ"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"បន្ទាត់បែងចែកខាងស្ដាំ <xliff:g id="PERCENT">%1$d</xliff:g> ភាគរយ"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"បានរក្សាទុកនៅក្នុង <xliff:g id="APP">%1$s</xliff:g> ក្នុងកម្រងព័ត៌មានការងារ"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ឯកសារ"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> បានរកឃើញរូបថតអេក្រង់នេះ។"</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> និងកម្មវិធីដែលបើកផ្សេងទៀតបានរកឃើញរូបថតអេក្រង់នេះ។"</string> <string name="screenrecord_name" msgid="2596401223859996572">"មុខងារថតវីដេអូអេក្រង់"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"កំពុងដំណើរការការថតអេក្រង់"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"ការជូនដំណឹងដែលកំពុងដំណើរការសម្រាប់រយៈពេលប្រើការថតសកម្មភាពអេក្រង់"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"មានអ្វីមួយខុសប្រក្រតី។ សូមព្យាយាមម្ដងទៀត។"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"កំពុងផ្ទុក"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ថេប្លេត"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើលកម្មវិធី"</string> <string name="controls_error_removed" msgid="6675638069846014366">"រកមិនឃើញទេ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"មិនអាចគ្រប់គ្រងបានទេ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 308707a027d3..dbc7e1596019 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"ಏನೋ ತಪ್ಪಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"ಲೋಡ್ ಆಗುತ್ತಿದೆ"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ಟ್ಯಾಬ್ಲೆಟ್"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"ನಿಮ್ಮ ಮಾಧ್ಯಮವನ್ನು ಬಿತ್ತರಿಸಲಾಗುತ್ತಿದೆ"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ಅನ್ನು ಬಿತ್ತರಿಸಲಾಗುತ್ತಿದೆ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ನಿಯಂತ್ರಣ ಲಭ್ಯವಿಲ್ಲ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 2e4aca717d9a..1595de32f1c0 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"문제가 발생했습니다. 다시 시도해 주세요."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"로드 중"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"태블릿"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"미디어 전송"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"<xliff:g id="APP_LABEL">%1$s</xliff:g> 전송 중"</string> <string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string> <string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"컨트롤을 사용할 수 없음"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index e4662ed68be3..653292c1b74b 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Бир жерден ката кетти. Кайра аракет кылыңыз."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Жүктөлүүдө"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"планшет"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Медиа тышкы экранга чыгарылууда"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"<xliff:g id="APP_LABEL">%1$s</xliff:g> түзмөгүнө чыгарылууда"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Башкара албайсыз"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 8b99ac3b5c48..ce929e910ef7 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"ມີບາງຢ່າງຜິດພາດເກີດຂຶ້ນ. ກະລຸນາລອງໃໝ່."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"ກຳລັງໂຫຼດ"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ແທັບເລັດ"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"ການກຳນົດບົດບາດສື່ຂອງທ່ານ"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"ການກຳນົດບົດບາດ <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ບໍ່ສາມາດໃຊ້ການຄວບຄຸມໄດ້"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 2c4d55b9124a..e153fe02626a 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Apatinė riba – <xliff:g id="PERCENT">%1$d</xliff:g> proc."</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Kairioji riba – <xliff:g id="PERCENT">%1$d</xliff:g> proc."</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Dešinioji riba – <xliff:g id="PERCENT">%1$d</xliff:g> proc."</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Išsaugota programoje „<xliff:g id="APP">%1$s</xliff:g>“ darbo profilyje"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Failai"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"„<xliff:g id="APPNAME">%1$s</xliff:g>“ aptiko šią ekrano kopiją."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"„<xliff:g id="APPNAME">%1$s</xliff:g>“ ir kitos atidarytos programos aptiko šią ekrano kopiją."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Ekrano vaizdo įrašytuvas"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Apdorojam. ekrano vaizdo įraš."</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Šiuo metu rodomas ekrano įrašymo sesijos pranešimas"</string> @@ -865,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Kažkas ne taip. Bandykite dar kartą."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Įkeliama"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"planšetinis kompiuteris"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Perduodama medija"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Perduodama programa „<xliff:g id="APP_LABEL">%1$s</xliff:g>“"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Valdiklis nepasiekiamas"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 412bfe8c78e3..2878f7dc030c 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Apakšmala: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Kreisā mala: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Labā mala: <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Saglabāts lietotnē <xliff:g id="APP">%1$s</xliff:g> darba profilā"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Faili"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> konstatēja, ka tika veikts ekrānuzņēmums."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> un citas atvērtas lietotnes konstatēja, ka tika veikts ekrānuzņēmums."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Ekrāna ierakstītājs"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekrāna ieraksta apstrāde"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Aktīvs paziņojums par ekrāna ierakstīšanas sesiju"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Radās kļūda. Mēģiniet vēlreiz."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Notiek ielāde"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"planšetdators"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Vadīkla nav pieejama"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 613dff3a20ea..b7d69cf301e4 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Нешто не е во ред. Обидете се повторно."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Се вчитува"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"таблет"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Не е најдено"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е достапна"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index f3848d537278..46258cb050b5 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"എന്തോ കുഴപ്പമുണ്ടായി. വീണ്ടും ശ്രമിക്കുക."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"ലോഡ് ചെയ്യുന്നു"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ടാബ്ലെറ്റ്"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"നിങ്ങളുടെ മീഡിയ കാസ്റ്റ് ചെയ്യുന്നു"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"<xliff:g id="APP_LABEL">%1$s</xliff:g> കാസ്റ്റ് ചെയ്യുന്നു"</string> <string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"കണ്ടെത്തിയില്ല"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"നിയന്ത്രണം ലഭ്യമല്ല"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 0b108a231d04..2ef821683a5e 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Алдаа гарлаа. Дахин оролдоно уу."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Ачаалж байна"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"таблет"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Хяналт боломжгүй байна"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 214c92f78840..c4fd4aae4827 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"काहीतरी चूक झाली. पुन्हा प्रयत्न करा."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"लोड करत आहे"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"टॅबलेट"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string> <string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"नियंत्रण उपलब्ध नाही"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index ff9897dab2a4..aa3626cf2c4f 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Kesilapan telah berlaku. Cuba lagi."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Memuatkan"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Menghantar media anda"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Menghantar <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kawalan tidak tersedia"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 8abb23c91152..6338abf68cc2 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"တစ်ခုခုမှားသွားသည်။ ထပ်စမ်းကြည့်ပါ။"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"ဖွင့်နေသည်"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"တက်ဘလက်"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"သင့်မီဒီယာကို ကာစ်လုပ်နေသည်"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ကို ကာစ်လုပ်နေသည်"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ထိန်းချုပ်မှု မရနိုင်ပါ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 4a129e84e8ad..9a9ca35e2c81 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Nedre grense <xliff:g id="PERCENT">%1$d</xliff:g> prosent"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Venstre grense <xliff:g id="PERCENT">%1$d</xliff:g> prosent"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Høyre grense <xliff:g id="PERCENT">%1$d</xliff:g> prosent"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Lagret i <xliff:g id="APP">%1$s</xliff:g> i jobbprofilen"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Filer"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> har registrert denne skjermdumpen."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> og andre åpne apper har registrert denne skjermdumpen."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Skjermopptaker"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skjermopptaket"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Vedvarende varsel for et skjermopptak"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Noe gikk galt. Prøv på nytt."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Laster inn"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"nettbrett"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrollen er utilgjengelig"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index e6292fc6f29a..e460e263d101 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"केही चिज गडबड भयो। फेरि प्रयास गर्नुहोस्।"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"लोड हुँदै छ"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ट्याब्लेट"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"तपाईंको मिडिया कास्ट गरिँदै छ"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"<xliff:g id="APP_LABEL">%1$s</xliff:g> कास्ट गरिँदै छ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string> <string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"नियन्त्रण उपलब्ध छैन"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 9fcc945fc0b9..8d67715eda59 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Ondergrens <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Linkergrens <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Rechtergrens <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Opgeslagen in <xliff:g id="APP">%1$s</xliff:g> in het werkprofiel."</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Bestanden"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> heeft dit screenshot waargenomen."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> en andere geopende apps hebben dit screenshot waargenomen."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Schermopname"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Schermopname verwerken"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Doorlopende melding voor een schermopname-sessie"</string> @@ -865,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Er is iets misgegaan. Probeer het opnieuw."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Laden"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Je media casten"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"<xliff:g id="APP_LABEL">%1$s</xliff:g> casten"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Beheeroptie niet beschikbaar"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 15a7ea775217..992cd863a1bc 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"କିଛି ତ୍ରୁଟି ହୋଇଛି। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"ଲୋଡ ହେଉଛି"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ଟାବଲେଟ"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ନିୟନ୍ତ୍ରଣ ଉପଲବ୍ଧ ନାହିଁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 03350a99900a..c814159eb64d 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"ਹੇਠਾਂ ਦੀ ਸੀਮਾ <xliff:g id="PERCENT">%1$d</xliff:g> ਫ਼ੀਸਦ"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"ਖੱਬੇ ਪਾਸੇ ਵਾਲੀ ਸੀਮਾ <xliff:g id="PERCENT">%1$d</xliff:g> ਫ਼ੀਸਦ"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"ਸੱਜੇ ਪਾਸੇ ਵਾਲੀ ਸੀਮਾ <xliff:g id="PERCENT">%1$d</xliff:g> ਫ਼ੀਸਦ"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ <xliff:g id="APP">%1$s</xliff:g> ਵਿੱਚ ਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ਫ਼ਾਈਲਾਂ"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> ਨੂੰ ਇਸ ਸਕ੍ਰੀਨਸ਼ਾਟ ਦਾ ਪਤਾ ਲੱਗਿਆ ਹੈ।"</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ਅਤੇ ਹੋਰ ਖੁੱਲ੍ਹੀਆਂ ਐਪਾਂ ਨੂੰ ਇਸ ਸਕ੍ਰੀਨਸ਼ਾਟ ਦਾ ਪਤਾ ਲੱਗਿਆ ਹੈ।"</string> <string name="screenrecord_name" msgid="2596401223859996572">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"ਕਿਸੇ ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਸੈਸ਼ਨ ਲਈ ਚੱਲ ਰਹੀ ਸੂਚਨਾ"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"ਲੋਡ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ਟੈਬਲੈੱਟ"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ਕੰਟਰੋਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 68c540f8431a..025dd66fd1f0 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Przycięcie dolnej krawędzi o <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Przycięcie lewej krawędzi o <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Przycięcie prawej krawędzi o <xliff:g id="PERCENT">%1$d</xliff:g> procent"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Zapisano w aplikacji <xliff:g id="APP">%1$s</xliff:g> w profilu służbowym"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Pliki"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"Aplikacja <xliff:g id="APPNAME">%1$s</xliff:g> wykryła ten zrzut ekranu."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Aplikacja <xliff:g id="APPNAME">%1$s</xliff:g> i inne aplikacje wykryły ten zrzut ekranu."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Nagrywanie ekranu"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Przetwarzam nagrywanie ekranu"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Stałe powiadomienie o sesji rejestrowania zawartości ekranu"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Coś poszło nie tak. Spróbuj ponownie."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Wczytuję"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Element jest niedostępny"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index accb35c5c4db..39feb0836f39 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Carregando"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Transmitindo sua mídia"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Transmitindo o app <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string> @@ -1016,7 +1018,7 @@ <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Um app de câmera está instalado"</string> <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• O app está disponível"</string> <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Pelo menos um dispositivo está disponível"</string> - <string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Mantenha o atalho pressionado"</string> + <string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Toque e pressione o atalho"</string> <string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancelar"</string> <string name="rear_display_bottom_sheet_confirm" msgid="4383356544661421206">"Virar agora"</string> <string name="rear_display_fold_bottom_sheet_title" msgid="6081542277622721548">"Abra o smartphone para tirar uma selfie melhor"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 9ee8afca1785..98f063f933ed 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Algo correu mal. Tente novamente."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"A carregar"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"A transmitir o conteúdo multimédia"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"A transmitir a app <xliff:g id="APP_LABEL">%1$s</xliff:g>…"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"O controlo está indisponível"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index accb35c5c4db..39feb0836f39 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Carregando"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Transmitindo sua mídia"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Transmitindo o app <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string> @@ -1016,7 +1018,7 @@ <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• Um app de câmera está instalado"</string> <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• O app está disponível"</string> <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• Pelo menos um dispositivo está disponível"</string> - <string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Mantenha o atalho pressionado"</string> + <string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Toque e pressione o atalho"</string> <string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Cancelar"</string> <string name="rear_display_bottom_sheet_confirm" msgid="4383356544661421206">"Virar agora"</string> <string name="rear_display_fold_bottom_sheet_title" msgid="6081542277622721548">"Abra o smartphone para tirar uma selfie melhor"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index a14475521787..bf26016b39c6 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"A apărut o eroare. Încearcă din nou."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Se încarcă"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tabletă"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verifică aplicația"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Comanda este indisponibilă"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 8ac0b14993e6..1a10a79b2c44 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Произошла ошибка. Повторите попытку."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Загрузка…"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"планшет"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Трансляция медиаконтента"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Трансляция: <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Управление недоступно"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 5e78e73333f5..217a6e348e3c 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"පහළ සීමාව සියයට <xliff:g id="PERCENT">%1$d</xliff:g>"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"වම් සීමාව සියයට <xliff:g id="PERCENT">%1$d</xliff:g>"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"දකුණු සීමාව සියයට <xliff:g id="PERCENT">%1$d</xliff:g>"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"කාර්යාල පැතිකඩේ <xliff:g id="APP">%1$s</xliff:g> තුළ සුරකින ලදි"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"ගොනු"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> මෙම තිර රුව අනාවරණය කර ගෙන ඇත."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> සහ අනෙකුත් විවෘත යෙදුම් මෙම තිර රුව අනාවරණය කර ගෙන ඇත."</string> <string name="screenrecord_name" msgid="2596401223859996572">"තිර රෙකෝඩරය"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"තිර පටිගත කිරීම සකසමින්"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"තිර පටිගත කිරීමේ සැසියක් සඳහා කෙරෙන දැනුම් දීම"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"යම් දෙයක් වැරදිණි. නැවත උත්සාහ කරන්න."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"පූරණය වේ"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ටැබ්ලටය"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"අක්රියයි, යෙදුම පරීක්ෂා කරන්න"</string> <string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"පාලනය ලබා ගත නොහැකිය"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 884848b2ee2e..f6f7b37d4afa 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"<xliff:g id="PERCENT">%1$d</xliff:g> %% dolnej hranice"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"<xliff:g id="PERCENT">%1$d</xliff:g> %% ľavej hranice"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"<xliff:g id="PERCENT">%1$d</xliff:g> %% pravej hranice"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Uložená v aplikácii <xliff:g id="APP">%1$s</xliff:g> v pracovnom profile"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"Aplikácia <xliff:g id="APPNAME">%1$s</xliff:g> zaznamenala túto snímku obrazovky."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> a ďalšie otvorené aplikácie zaznamenali túto snímku obrazovky."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Spracúva sa záznam obrazovky"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Zobrazuje sa upozornenie týkajúce sa relácie záznamu obrazovky"</string> @@ -865,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Niečo sa pokazilo. Skúste to znova."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Načítava sa"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Prenášajú sa médiá"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Prenáša sa <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládač nie je k dispozícii"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 6b04eab80816..c188d4577524 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Prišlo je do napake. Poskusite znova."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Nalaganje"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablični računalnik"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolnik ni na voljo"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index b0fdbe2dfecb..c9789a967929 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Ndodhi një gabim. Provo përsëri."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Po ngarkohet"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Po transmeton median tënde"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Po transmeton <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolli është i padisponueshëm"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 35de274ca75b..d756401277a7 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Дошло је до грешке. Пробајте поново."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Учитава се"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"таблет"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Контрола није доступна"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 356c6747e725..d12c25ff5a4b 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Något gick fel. Försök igen."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Läser in"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"surfplatta"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Styrning är inte tillgänglig"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index abaad5072873..564de43b90a7 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Mpaka wa sehemu ya chini wa asilimia <xliff:g id="PERCENT">%1$d</xliff:g>"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Mpaka wa sehemu ya kushoto wa asilimia <xliff:g id="PERCENT">%1$d</xliff:g>"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Mpaka wa sehemu ya kulia wa asilimia <xliff:g id="PERCENT">%1$d</xliff:g>"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Imehifadhiwa kwenye <xliff:g id="APP">%1$s</xliff:g> katika wasifu wa kazini"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Faili"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> imetambua picha hii ya skrini."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> na zingine zinazotumika zimetambua picha hii ya skrini."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Kinasa Skrini"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Inachakata rekodi ya skrini"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Arifa inayoendelea ya kipindi cha kurekodi skrini"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Hitilafu fulani imetokea. Jaribu tena."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Inapakia"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"kompyuta kibao"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kidhibiti hakipatikani"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index e3dcccb6dc94..b20bd37460b7 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"கீழ் எல்லை <xliff:g id="PERCENT">%1$d</xliff:g> சதவீதம்"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"இடது எல்லை <xliff:g id="PERCENT">%1$d</xliff:g> சதவீதம்"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"வலது எல்லை <xliff:g id="PERCENT">%1$d</xliff:g> சதவீதம்"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"பணிக் கணக்கில் உள்ள <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸில் சேமிக்கப்பட்டது"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Files"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"இந்த ஸ்கிரீன்ஷாட்டை <xliff:g id="APPNAME">%1$s</xliff:g> கண்டறிந்துள்ளது."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"இந்த ஸ்கிரீன்ஷாட்டை <xliff:g id="APPNAME">%1$s</xliff:g> மற்றும் திறந்திருக்கும் பிற ஆப்ஸ் கண்டறிந்துள்ளன."</string> <string name="screenrecord_name" msgid="2596401223859996572">"ஸ்கிரீன் ரெக்கார்டர்"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ஸ்க்ரீன் ரெக்கார்டிங் செயலாக்கப்படுகிறது"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"திரை ரெக்கார்டிங் அமர்விற்கான தொடர் அறிவிப்பு"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"ஏதோ தவறாகிவிட்டது. மீண்டும் முயலவும்."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"ஏற்றுகிறது"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"டேப்லெட்"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string> <string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"கட்டுப்பாடு இல்லை"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index d50b1cfe41c3..07196710c6a5 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"ఏదో తప్పు జరిగింది. మళ్లీ ట్రై చేయండి."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"లోడ్ అవుతోంది"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"టాబ్లెట్"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"మీ మీడియా ప్రసారం అవుతోంది"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ప్రసారం అవుతోంది"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ఇన్యాక్టివ్, యాప్ చెక్ చేయండి"</string> <string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 930123f871b4..90617cac58ae 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"เกิดข้อผิดพลาด โปรดลองอีกครั้ง"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"กำลังโหลด"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"แท็บเล็ต"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"กำลังแคสต์สื่อ"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"กำลังแคสต์ <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ใช้การควบคุมไม่ได้"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 45697d991713..4eaa89ca0ac5 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Nagkaproblema. Subukan ulit."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Naglo-load"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Hindi available ang kontrol"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index a145f7b3bafe..2e53e64f8eb9 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Alt sınır yüzde <xliff:g id="PERCENT">%1$d</xliff:g>"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Sol sınır yüzde <xliff:g id="PERCENT">%1$d</xliff:g>"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Sağ sınır yüzde <xliff:g id="PERCENT">%1$d</xliff:g>"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"İş profilinde <xliff:g id="APP">%1$s</xliff:g> uygulamasına kaydedildi"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Dosyalar"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> bu ekran görüntüsünü algıladı."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ve diğer açık uygulamalar bu ekran görüntüsünü algıladı."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Ekran Kaydedicisi"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran kaydı işleniyor"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekran kaydı oturumu için devam eden bildirim"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Bir hata oluştu. Tekrar deneyin."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Yükleme"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"tablet"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol kullanılamıyor"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 5cb17d1efde0..8b5f7b69e01e 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Знизу на <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Зліва на <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Справа на <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Збережено в додатку <xliff:g id="APP">%1$s</xliff:g> у робочому профілі"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Файли"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"Додаток <xliff:g id="APPNAME">%1$s</xliff:g> виявив цей знімок екрана."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> та інші відкриті додатки виявили цей знімок екрана."</string> <string name="screenrecord_name" msgid="2596401223859996572">"Запис відео з екрана"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обробка записування екрана"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Сповіщення про сеанс запису екрана"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Сталася помилка. Повторіть спробу."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Завантаження"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"планшет"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Елемент керування недоступний"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 48ef8c41cc6d..c1bca22ad556 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"نیچے کا احاطہ <xliff:g id="PERCENT">%1$d</xliff:g> فیصد"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"بایاں احاطہ <xliff:g id="PERCENT">%1$d</xliff:g> فیصد"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"دایاں احاطہ <xliff:g id="PERCENT">%1$d</xliff:g> فیصد"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"دفتری پروفائل میں <xliff:g id="APP">%1$s</xliff:g> میں محفوظ کی گئی"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"فائلز"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> نے اس اسکرین شاٹ کا پتا لگایا۔"</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> اور دیگر کھلی ایپس نے اس اسکرین شاٹ کا پتا لگایا۔"</string> <string name="screenrecord_name" msgid="2596401223859996572">"اسکرین ریکارڈر"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"سکرین ریکارڈنگ پروسیس ہورہی ہے"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"اسکرین ریکارڈ سیشن کیلئے جاری اطلاع"</string> @@ -865,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"کچھ غلط ہوگیا۔ پھر کوشش کریں۔"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"لوڈ ہو رہا ہے"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ٹیبلیٹ"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string> <string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"کنٹرول دستیاب نہیں ہے"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 573b33a57f36..284193b78a54 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"Quyi chegara <xliff:g id="PERCENT">%1$d</xliff:g> foiz"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Chap chegara <xliff:g id="PERCENT">%1$d</xliff:g> foiz"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Oʻng chegara <xliff:g id="PERCENT">%1$d</xliff:g> foiz"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Ish profilidagi <xliff:g id="APP">%1$s</xliff:g> ilovasiga saqlandi"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Fayllar"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"Bu skrinshotda <xliff:g id="APPNAME">%1$s</xliff:g> aniqlandi."</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Bu skrinshotda <xliff:g id="APPNAME">%1$s</xliff:g> va boshqa ochiq ilovalar aniqlandi"</string> <string name="screenrecord_name" msgid="2596401223859996572">"Ekrandan yozib olish"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran yozib olinmoqda"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekrandan yozib olish seansi uchun joriy bildirishnoma"</string> @@ -865,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Xatolik yuz berdi. Qayta urining."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Yuklanmoqda"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"planshet"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Mediani translatsiya qilish"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Translatsiya qilinmoqda: <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Boshqarish imkonsiz"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 2d5f598ff438..fe77c10ac22d 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Đã xảy ra lỗi. Hãy thử lại."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Đang tải"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"máy tính bảng"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Không có chức năng điều khiển"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index b3aef64aceed..3cd6a69ccf55 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -91,13 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"底部边界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"左侧边界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"右侧边界百分之 <xliff:g id="PERCENT">%1$d</xliff:g>"</string> - <!-- no translation found for screenshot_work_profile_notification (203041724052970693) --> - <skip /> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"已保存到工作资料名下的 <xliff:g id="APP">%1$s</xliff:g>中"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"文件"</string> - <!-- no translation found for screenshot_detected_template (7940376642921719915) --> - <skip /> - <!-- no translation found for screenshot_detected_multiple_template (7644827792093819241) --> - <skip /> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> 检测到此屏幕截图。"</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> 及其他打开的应用检测到此屏幕截图。"</string> <string name="screenrecord_name" msgid="2596401223859996572">"屏幕录制器"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在处理屏幕录制视频"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"持续显示屏幕录制会话通知"</string> @@ -655,7 +652,7 @@ <string name="right_keycode" msgid="2480715509844798438">"向右键码"</string> <string name="left_icon" msgid="5036278531966897006">"向左图标"</string> <string name="right_icon" msgid="1103955040645237425">"向右图标"</string> - <string name="drag_to_add_tiles" msgid="8933270127508303672">"按住并拖动即可添加图块"</string> + <string name="drag_to_add_tiles" msgid="8933270127508303672">"按住并拖动即可添加功能块"</string> <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"按住并拖动即可重新排列图块"</string> <string name="drag_to_remove_tiles" msgid="4682194717573850385">"拖动到此处即可移除"</string> <string name="drag_to_remove_disabled" msgid="933046987838658850">"您至少需要 <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> 个卡片"</string> @@ -673,15 +670,15 @@ </string-array> <string name="tuner_low_priority" msgid="8412666814123009820">"显示低优先级的通知图标"</string> <string name="other" msgid="429768510980739978">"其他"</string> - <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除图块"</string> - <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"将图块添加到末尾"</string> - <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移动图块"</string> - <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"添加图块"</string> + <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除功能块"</string> + <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"将功能块添加到末尾"</string> + <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移动功能块"</string> + <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"添加功能块"</string> <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"移至 <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"添加到位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"已添加卡片"</string> - <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"已移除卡片"</string> + <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"已添加功能块"</string> + <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"已移除功能块"</string> <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快捷设置编辑器。"</string> <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>通知:<xliff:g id="ID_2">%2$s</xliff:g>"</string> <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"打开设置。"</string> @@ -865,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"出了点问题,请重试。"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"正在加载"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"平板电脑"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"投放您的媒体"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"投放 <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string> <string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"控件不可用"</string> @@ -968,9 +967,9 @@ <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切换网络,请断开以太网连接"</string> <string name="wifi_scan_notify_message" msgid="3753839537448621794">"为了提升设备的使用体验,即使 WLAN 已关闭,应用和服务仍可以随时扫描 WLAN 网络。您可以在 WLAN 扫描设置中更改此设置。"<annotation id="link">"更改"</annotation></string> <string name="turn_off_airplane_mode" msgid="8425587763226548579">"关闭飞行模式"</string> - <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"“<xliff:g id="APPNAME">%1$s</xliff:g>”希望将以下图块添加到“快捷设置”"</string> - <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"添加图块"</string> - <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不添加图块"</string> + <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"“<xliff:g id="APPNAME">%1$s</xliff:g>”希望将以下功能块添加到“快捷设置”"</string> + <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"添加功能块"</string> + <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不添加功能块"</string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"选择用户"</string> <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# 个应用处于活动状态}other{# 个应用处于活动状态}}"</string> <string name="fgs_dot_content_description" msgid="2865071539464777240">"新信息"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index f13dbf05a707..e499fe5beda3 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -91,10 +91,10 @@ <string name="screenshot_bottom_boundary_pct" msgid="3880821519814946478">"下方邊界 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"左方邊界 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"右方邊界 <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> - <string name="screenshot_work_profile_notification" msgid="203041724052970693">"已儲存在工作資料夾的「<xliff:g id="APP">%1$s</xliff:g>」中"</string> + <string name="screenshot_work_profile_notification" msgid="203041724052970693">"已儲存在工作設定檔的「<xliff:g id="APP">%1$s</xliff:g>」中"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"檔案"</string> - <string name="screenshot_detected_template" msgid="7940376642921719915">"「<xliff:g id="APPNAME">%1$s</xliff:g>」偵測到這張螢幕截圖。"</string> - <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"「<xliff:g id="APPNAME">%1$s</xliff:g>」和其他開啟的應用程式偵測到這張螢幕截圖。"</string> + <string name="screenshot_detected_template" msgid="7940376642921719915">"<xliff:g id="APPNAME">%1$s</xliff:g> 偵測到此螢幕截圖。"</string> + <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> 和其他開啟的應用程式偵測到此螢幕截圖。"</string> <string name="screenrecord_name" msgid="2596401223859996572">"螢幕畫面錄影工具"</string> <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在處理螢幕錄影內容"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示錄影畫面工作階段通知"</string> @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"發生錯誤,請再試一次。"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"正在載入"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"平板電腦"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string> <string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制功能"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 0ca96fb8a6c8..26c60e0b3340 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -862,6 +862,10 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"發生錯誤,請再試一次。"</string> <string name="media_transfer_loading" msgid="5544017127027152422">"載入中"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"平板電腦"</string> + <!-- no translation found for media_transfer_receiver_content_description_unknown_app (7381771464846263667) --> + <skip /> + <!-- no translation found for media_transfer_receiver_content_description_with_app_name (8555975056850659389) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string> <string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制項"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 29fb0e9a940e..b585b6ccbada 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -862,6 +862,8 @@ <string name="media_transfer_failed" msgid="7955354964610603723">"Kukhona okungahambanga kahle. Zama futhi."</string> <string name="media_transfer_loading" msgid="5544017127027152422">"Iyalayisha"</string> <string name="media_ttt_default_device_type" msgid="4457646436153370169">"ithebulethi"</string> + <string name="media_transfer_receiver_content_description_unknown_app" msgid="7381771464846263667">"Isakaza imidiya yakho"</string> + <string name="media_transfer_receiver_content_description_with_app_name" msgid="8555975056850659389">"Isakaza i-<xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Ukulawula akutholakali"</string> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index f46266b339d1..e346fe4ab3ef 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -214,5 +214,12 @@ <attr name="biometricsEnrollProgressHelp" format="reference|color" /> <attr name="biometricsEnrollProgressHelpWithTalkback" format="reference|color" /> </declare-styleable> + + <declare-styleable name="SeekBarWithIconButtonsView_Layout"> + <attr name="max" format="integer" /> + <attr name="progress" format="integer" /> + <attr name="iconStartContentDescription" format="reference" /> + <attr name="iconEndContentDescription" format="reference" /> + </declare-styleable> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 371f00189ad6..031d40e074a3 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -81,7 +81,7 @@ <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" --> <string name="quick_settings_tiles_stock" translatable="false"> - internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream + internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,color_correction,dream,font_scaling </string> <!-- The tiles to display in QuickSettings --> @@ -654,7 +654,7 @@ <item>26</item> <!-- MOUTH_COVERING_DETECTED --> </integer-array> - <!-- Which device wake-ups will trigger face auth. These values correspond with + <!-- Which device wake-ups will trigger passive auth. These values correspond with PowerManager#WakeReason. --> <integer-array name="config_face_auth_wake_up_triggers"> <item>1</item> <!-- WAKE_REASON_POWER_BUTTON --> @@ -663,6 +663,7 @@ <item>7</item> <!-- WAKE_REASON_WAKE_MOTION --> <item>9</item> <!-- WAKE_REASON_LID --> <item>10</item> <!-- WAKE_REASON_DISPLAY_GROUP_ADDED --> + <item>12</item> <!-- WAKE_REASON_UNFOLD_DEVICE --> <item>15</item> <!-- WAKE_REASON_TAP --> <item>16</item> <!-- WAKE_REASON_LIFT --> <item>17</item> <!-- WAKE_REASON_BIOMETRIC --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 939171479d32..d48ea214e8d9 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1409,6 +1409,9 @@ <dimen name="padding_above_predefined_icon_for_small">4dp</dimen> <dimen name="padding_between_suppressed_layout_items">8dp</dimen> + <!-- Seekbar with icon buttons --> + <dimen name="seekbar_icon_size">24dp</dimen> + <!-- Accessibility floating menu --> <dimen name="accessibility_floating_menu_elevation">3dp</dimen> <dimen name="accessibility_floating_menu_stroke_width">1dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 1966f2b27c9f..e6ac59e6b106 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -660,6 +660,8 @@ <string name="quick_settings_inversion_label">Color inversion</string> <!-- QuickSettings: Label for the toggle that controls whether display color correction is enabled. [CHAR LIMIT=NONE] --> <string name="quick_settings_color_correction_label">Color correction</string> + <!-- QuickSettings: Label for font size scaling. [CHAR LIMIT=NONE] --> + <string name="quick_settings_font_scaling_label">Font size</string> <!-- QuickSettings: Control panel: Label for button that navigates to user settings. [CHAR LIMIT=NONE] --> <string name="quick_settings_more_user_settings">Manage users</string> <!-- QuickSettings: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] --> @@ -2181,6 +2183,14 @@ <!-- Title of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=25] --> <string name="inattentive_sleep_warning_title">Standby</string> + <!-- Font scaling --> + <!-- Font scaling: Quick Settings dialog title [CHAR LIMIT=30] --> + <string name="font_scaling_dialog_title">Font Size</string> + <!-- Content Description for the icon button to make fonts smaller. [CHAR LIMIT=30] --> + <string name="font_scaling_smaller">Make smaller</string> + <!-- Content Description for the icon button to make fonts larger. [CHAR LIMIT=30] --> + <string name="font_scaling_larger">Make larger</string> + <!-- Window Magnification strings --> <!-- Title for Magnification Window [CHAR LIMIT=NONE] --> <string name="magnification_window_title">Magnification Window</string> @@ -2464,7 +2474,10 @@ <string name="media_output_broadcast_update_error">Can\u2019t save. Try again.</string> <!-- The error message when Broadcast name/code update failed and can't change again[CHAR LIMIT=60] --> <string name="media_output_broadcast_last_update_error">Can\u2019t save.</string> - + <!-- The hint message when Broadcast code is less than 4 characters [CHAR LIMIT=60] --> + <string name="media_output_broadcast_code_hint_no_less_than_min">Use at least 4 characters</string> + <!-- The hint message when Broadcast code is more than 16 characters [CHAR LIMIT=60] --> + <string name="media_output_broadcast_code_hint_no_more_than_max">Use fewer than 16 characters</string> <!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]--> <string name="build_number_clip_data_label">Build number</string> @@ -2780,15 +2793,15 @@ <!-- Text for education page of cancel button to hide the page. [CHAR_LIMIT=NONE] --> <string name="rear_display_bottom_sheet_cancel">Cancel</string> <!-- Text for the user to confirm they flipped the device around. [CHAR_LIMIT=NONE] --> - <string name="rear_display_bottom_sheet_confirm">Flip now</string> + <string name="rear_display_bottom_sheet_confirm">Switch screens now</string> <!-- Text for education page title to guide user to unfold phone. [CHAR_LIMIT=50] --> - <string name="rear_display_fold_bottom_sheet_title">Unfold phone for a better selfie</string> - <!-- Text for education page title to guide user to flip to the front display. [CHAR_LIMIT=50] --> - <string name="rear_display_unfold_bottom_sheet_title">Flip to front display for a better selfie?</string> + <string name="rear_display_folded_bottom_sheet_title">Unfold phone</string> + <!-- Text for education page title to guide user to switch to the front display. [CHAR_LIMIT=50] --> + <string name="rear_display_unfolded_bottom_sheet_title">Switch screens?</string> <!-- Text for education page description to suggest user to use rear selfie capture. [CHAR_LIMIT=NONE] --> - <string name="rear_display_bottom_sheet_description">Use the rear-facing camera for a wider photo with higher resolution.</string> - <!-- Text for education page description to warn user that the display will turn off if the button is clicked. [CHAR_LIMIT=NONE] --> - <string name="rear_display_bottom_sheet_warning"><b>✱ This screen will turn off</b></string> + <string name="rear_display_folded_bottom_sheet_description">For higher resolution, use the rear camera</string> + <!-- Text for unfolded education page description to suggest user to use rear selfie capture. [CHAR_LIMIT=NONE] --> + <string name="rear_display_unfolded_bottom_sheet_description">For higher resolution, flip the phone</string> <!-- Text for education page content description for folded animation. [CHAR_LIMIT=NONE] --> <string name="rear_display_accessibility_folded_animation">Foldable device being unfolded</string> <!-- Text for education page content description for unfolded animation. [CHAR_LIMIT=NONE] --> diff --git a/packages/SystemUI/res/values/tiles_states_strings.xml b/packages/SystemUI/res/values/tiles_states_strings.xml index c8095510e2c2..7020d548f6b0 100644 --- a/packages/SystemUI/res/values/tiles_states_strings.xml +++ b/packages/SystemUI/res/values/tiles_states_strings.xml @@ -318,4 +318,14 @@ <item>Off</item> <item>On</item> </string-array> + + <!-- State names for font scaling tile: unavailable, off, on. + This subtitle is shown when the tile is in that particular state but does not set its own + subtitle, so some of these may never appear on screen. They should still be translated as + if they could appear. [CHAR LIMIT=32] --> + <string-array name="tile_states_font_scaling"> + <item>Unavailable</item> + <item>Off</item> + <item>On</item> + </string-array> </resources>
\ No newline at end of file diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml index d9c81af54a12..5129fc0337e0 100644 --- a/packages/SystemUI/res/xml/media_session_collapsed.xml +++ b/packages/SystemUI/res/xml/media_session_collapsed.xml @@ -73,11 +73,12 @@ android:layout_height="wrap_content" android:layout_marginEnd="@dimen/qs_media_info_spacing" android:layout_marginBottom="@dimen/qs_media_padding" - android:layout_marginTop="0dp" + android:layout_marginTop="@dimen/qs_media_icon_offset" app:layout_constraintStart_toStartOf="@id/header_title" app:layout_constraintEnd_toStartOf="@id/header_artist" app:layout_constraintTop_toTopOf="@id/header_artist" - app:layout_constraintBottom_toTopOf="@id/media_action_barrier_top" + app:layout_constraintBottom_toBottomOf="@id/header_artist" + app:layout_constraintVertical_bias="0" app:layout_constraintHorizontal_bias="0" app:layout_constraintHorizontal_chainStyle="packed" /> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index 037a71ea3eac..65dedc6eaf4b 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -43,6 +43,7 @@ public class QuickStepContract { public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy"; public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius"; public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners"; + public static final String KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER = "extra_unfold_animation"; // See ISysuiUnlockAnimationController.aidl public static final String KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER = "unlock_animation"; diff --git a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt index 54ae84f97b17..ead1a100f75b 100644 --- a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt +++ b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt @@ -303,9 +303,18 @@ class ActiveUnlockConfig @Inject constructor( pw.println(" requestActiveUnlockOnWakeup=$requestActiveUnlockOnWakeup") pw.println(" requestActiveUnlockOnUnlockIntent=$requestActiveUnlockOnUnlockIntent") pw.println(" requestActiveUnlockOnBioFail=$requestActiveUnlockOnBioFail") - pw.println(" requestActiveUnlockOnUnlockIntentWhenBiometricEnrolled=${ - onUnlockIntentWhenBiometricEnrolled.map { BiometricType.values()[it] } - }") + + val onUnlockIntentWhenBiometricEnrolledString = + onUnlockIntentWhenBiometricEnrolled.map { + for (biometricType in BiometricType.values()) { + if (biometricType.intValue == it) { + return@map biometricType.name + } + } + return@map "UNKNOWN" + } + pw.println(" requestActiveUnlockOnUnlockIntentWhenBiometricEnrolled=" + + "$onUnlockIntentWhenBiometricEnrolledString") pw.println(" requestActiveUnlockOnFaceError=$faceErrorsToTriggerBiometricFailOn") pw.println(" requestActiveUnlockOnFaceAcquireInfo=" + "$faceAcquireInfoToTriggerBiometricFailOn") diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 4acbb0aaf1d8..0326b6d3edca 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -209,7 +209,6 @@ public class KeyguardClockSwitch extends RelativeLayout { if (!animate) { out.setAlpha(0f); - out.setVisibility(INVISIBLE); in.setAlpha(1f); in.setVisibility(VISIBLE); mStatusArea.setTranslationY(statusAreaYTranslation); @@ -225,10 +224,7 @@ public class KeyguardClockSwitch extends RelativeLayout { direction * -mClockSwitchYAmount)); mClockOutAnim.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { - if (mClockOutAnim == animation) { - out.setVisibility(INVISIBLE); - mClockOutAnim = null; - } + mClockOutAnim = null; } }); @@ -242,9 +238,7 @@ public class KeyguardClockSwitch extends RelativeLayout { mClockInAnim.setStartDelay(CLOCK_OUT_MILLIS / 2); mClockInAnim.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { - if (mClockInAnim == animation) { - mClockInAnim = null; - } + mClockInAnim = null; } }); @@ -257,9 +251,7 @@ public class KeyguardClockSwitch extends RelativeLayout { mStatusAreaAnim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); mStatusAreaAnim.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { - if (mStatusAreaAnim == animation) { - mStatusAreaAnim = null; - } + mStatusAreaAnim = null; } }); mStatusAreaAnim.start(); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index 879a95c4df5d..baaeb2a1b3a5 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -404,6 +404,10 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS int clockHeight = clock.getLargeClock().getView().getHeight(); return frameHeight / 2 + clockHeight / 2 + mKeyguardLargeClockTopMargin / -2; } else { + // This is only called if we've never shown the large clock as the frame is inflated + // with 'gone', but then the visibility is never set when it is animated away by + // KeyguardClockSwitch, instead it is removed from the view hierarchy. + // TODO(b/261755021): Cleanup Large Frame Visibility int clockHeight = clock.getSmallClock().getView().getHeight(); return clockHeight + statusBarHeaderHeight + mKeyguardSmallClockTopMargin; } @@ -421,11 +425,15 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS if (mLargeClockFrame.getVisibility() == View.VISIBLE) { return clock.getLargeClock().getView().getHeight(); } else { + // Is not called except in certain edge cases, see comment in getClockBottom + // TODO(b/261755021): Cleanup Large Frame Visibility return clock.getSmallClock().getView().getHeight(); } } boolean isClockTopAligned() { + // Returns false except certain edge cases, see comment in getClockBottom + // TODO(b/261755021): Cleanup Large Frame Visibility return mLargeClockFrame.getVisibility() != View.VISIBLE; } diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java index 41111e3d3c6c..b30a0e010e4b 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java @@ -51,6 +51,7 @@ class NumPadAnimator { private float mStartRadius; private float mEndRadius; private int mHeight; + private boolean mInitialized; private static final int EXPAND_ANIMATION_MS = 100; private static final int EXPAND_COLOR_ANIMATION_MS = 50; @@ -95,9 +96,13 @@ class NumPadAnimator { mHeight = height; mStartRadius = height / 2f; mEndRadius = height / 4f; - mBackground.setCornerRadius(mStartRadius); mExpandAnimator.setFloatValues(mStartRadius, mEndRadius); mContractAnimator.setFloatValues(mEndRadius, mStartRadius); + // Set initial corner radius. + if (!mInitialized) { + mBackground.setCornerRadius(mStartRadius); + mInitialized = true; + } } /** diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java index 676979cd3931..b1a83fbda7de 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java @@ -18,13 +18,12 @@ package com.android.keyguard.dagger; import android.content.Context; import android.content.res.Resources; -import android.os.Handler; -import android.os.UserHandle; import android.view.LayoutInflater; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Application; +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; @@ -34,6 +33,8 @@ import com.android.systemui.shared.clocks.DefaultClockProvider; import dagger.Module; import dagger.Provides; +import kotlinx.coroutines.CoroutineDispatcher; +import kotlinx.coroutines.CoroutineScope; /** Dagger Module for clocks. */ @Module @@ -44,17 +45,23 @@ public abstract class ClockRegistryModule { public static ClockRegistry getClockRegistry( @Application Context context, PluginManager pluginManager, - @Main Handler handler, + @Application CoroutineScope scope, + @Main CoroutineDispatcher mainDispatcher, + @Background CoroutineDispatcher bgDispatcher, FeatureFlags featureFlags, @Main Resources resources, LayoutInflater layoutInflater) { - return new ClockRegistry( + ClockRegistry registry = new ClockRegistry( context, pluginManager, - handler, + scope, + mainDispatcher, + bgDispatcher, featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS), - UserHandle.USER_ALL, + /* handleAllUsers= */ true, new DefaultClockProvider(context, layoutInflater, resources), context.getString(R.string.lockscreen_clock_id_fallback)); + registry.registerListeners(); + return registry; } } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt new file mode 100644 index 000000000000..799a4d597168 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility + +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tiles.ColorCorrectionTile +import com.android.systemui.qs.tiles.ColorInversionTile +import com.android.systemui.qs.tiles.DreamTile +import com.android.systemui.qs.tiles.FontScalingTile +import com.android.systemui.qs.tiles.NightDisplayTile +import com.android.systemui.qs.tiles.OneHandedModeTile +import com.android.systemui.qs.tiles.ReduceBrightColorsTile +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import dagger.multibindings.StringKey + +@Module +interface AccessibilityModule { + + /** Inject ColorInversionTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(ColorInversionTile.TILE_SPEC) + fun bindColorInversionTile(colorInversionTile: ColorInversionTile): QSTileImpl<*> + + /** Inject NightDisplayTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(NightDisplayTile.TILE_SPEC) + fun bindNightDisplayTile(nightDisplayTile: NightDisplayTile): QSTileImpl<*> + + /** Inject ReduceBrightColorsTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(ReduceBrightColorsTile.TILE_SPEC) + fun bindReduceBrightColorsTile(reduceBrightColorsTile: ReduceBrightColorsTile): QSTileImpl<*> + + /** Inject OneHandedModeTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(OneHandedModeTile.TILE_SPEC) + fun bindOneHandedModeTile(oneHandedModeTile: OneHandedModeTile): QSTileImpl<*> + + /** Inject ColorCorrectionTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(ColorCorrectionTile.TILE_SPEC) + fun bindColorCorrectionTile(colorCorrectionTile: ColorCorrectionTile): QSTileImpl<*> + + /** Inject DreamTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(DreamTile.TILE_SPEC) + fun bindDreamTile(dreamTile: DreamTile): QSTileImpl<*> + + /** Inject FontScalingTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(FontScalingTile.TILE_SPEC) + fun bindFontScalingTile(fontScalingTile: FontScalingTile): QSTileImpl<*> +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt new file mode 100644 index 000000000000..54f933ae6d09 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.accessibility.fontscaling + +import android.content.Context +import android.content.pm.ActivityInfo +import android.content.res.Configuration +import android.os.Bundle +import android.provider.Settings +import android.view.LayoutInflater +import android.widget.Button +import android.widget.SeekBar +import android.widget.SeekBar.OnSeekBarChangeListener +import android.widget.TextView +import com.android.systemui.R +import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView +import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.util.settings.SystemSettings + +/** The Dialog that contains a seekbar for changing the font size. */ +class FontScalingDialog(context: Context, private val systemSettings: SystemSettings) : + SystemUIDialog(context) { + private val strEntryValues: Array<String> = + context.resources.getStringArray(com.android.settingslib.R.array.entryvalues_font_size) + private lateinit var title: TextView + private lateinit var doneButton: Button + private lateinit var seekBarWithIconButtonsView: SeekBarWithIconButtonsView + + private val configuration: Configuration = + Configuration(context.getResources().getConfiguration()) + + override fun onCreate(savedInstanceState: Bundle?) { + setTitle(R.string.font_scaling_dialog_title) + setView(LayoutInflater.from(context).inflate(R.layout.font_scaling_dialog, null)) + setPositiveButton( + R.string.quick_settings_done, + /* onClick = */ null, + /* dismissOnClick = */ true + ) + super.onCreate(savedInstanceState) + + title = requireViewById(com.android.internal.R.id.alertTitle) + doneButton = requireViewById(com.android.internal.R.id.button1) + seekBarWithIconButtonsView = requireViewById(R.id.font_scaling_slider) + + seekBarWithIconButtonsView.setMax((strEntryValues).size - 1) + + val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, 1.0f) + seekBarWithIconButtonsView.setProgress(fontSizeValueToIndex(currentScale)) + + seekBarWithIconButtonsView.setOnSeekBarChangeListener( + object : OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { + systemSettings.putString(Settings.System.FONT_SCALE, strEntryValues[progress]) + } + + override fun onStartTrackingTouch(seekBar: SeekBar) { + // Do nothing + } + + override fun onStopTrackingTouch(seekBar: SeekBar) { + // Do nothing + } + } + ) + doneButton.setOnClickListener { dismiss() } + } + + private fun fontSizeValueToIndex(value: Float): Int { + var lastValue = strEntryValues[0].toFloat() + for (i in 1 until strEntryValues.size) { + val thisValue = strEntryValues[i].toFloat() + if (value < lastValue + (thisValue - lastValue) * .5f) { + return i - 1 + } + lastValue = thisValue + } + return strEntryValues.size - 1 + } + + override fun onConfigurationChanged(configuration: Configuration) { + super.onConfigurationChanged(configuration) + + val configDiff = configuration.diff(this.configuration) + this.configuration.setTo(configuration) + + if (configDiff and ActivityInfo.CONFIG_FONT_SCALE != 0) { + title.post { + title.setTextAppearance(R.style.TextAppearance_Dialog_Title) + doneButton.setTextAppearance(R.style.Widget_Dialog_Button) + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatterySaverModule.kt b/packages/SystemUI/src/com/android/systemui/battery/BatterySaverModule.kt new file mode 100644 index 000000000000..41737902983a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/battery/BatterySaverModule.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.battery + +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tiles.BatterySaverTile +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import dagger.multibindings.StringKey + +@Module +interface BatterySaverModule { + + /** Inject BatterySaverTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(BatterySaverTile.TILE_SPEC) + fun bindBatterySaverTile(batterySaverTile: BatterySaverTile): QSTileImpl<*> +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt index 1f6f6d97680c..3ea3cd171062 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt @@ -18,6 +18,7 @@ package com.android.systemui.biometrics import android.annotation.RawRes import android.content.Context +import android.content.Context.FINGERPRINT_SERVICE import android.content.res.Configuration import android.hardware.fingerprint.FingerprintManager import android.view.DisplayInfo @@ -66,16 +67,11 @@ open class AuthBiometricFingerprintIconController( R.dimen.biometric_dialog_fingerprint_icon_width), context.resources.getDimensionPixelSize( R.dimen.biometric_dialog_fingerprint_icon_height)) - var sideFps = false - (context.getSystemService(Context.FINGERPRINT_SERVICE) - as FingerprintManager?)?.let { fpm -> - for (prop in fpm.sensorPropertiesInternal) { - if (prop.isAnySidefpsType) { - sideFps = true - } - } - } - isSideFps = sideFps + isSideFps = + (context.getSystemService(FINGERPRINT_SERVICE) as FingerprintManager?)?.let { fpm -> + fpm.sensorPropertiesInternal.any { it.isAnySidefpsType } + } ?: false + preloadAssets(context) val displayInfo = DisplayInfo() context.display?.getDisplayInfo(displayInfo) if (isSideFps && getRotationFromDefault(displayInfo.rotation) == Surface.ROTATION_180) { @@ -329,6 +325,40 @@ open class AuthBiometricFingerprintIconController( else -> null } + private fun preloadAssets(context: Context) { + if (isSideFps) { + cacheLottieAssetsInContext( + context, + R.raw.biometricprompt_fingerprint_to_error_landscape, + R.raw.biometricprompt_folded_base_bottomright, + R.raw.biometricprompt_folded_base_default, + R.raw.biometricprompt_folded_base_topleft, + R.raw.biometricprompt_landscape_base, + R.raw.biometricprompt_portrait_base_bottomright, + R.raw.biometricprompt_portrait_base_topleft, + R.raw.biometricprompt_symbol_error_to_fingerprint_landscape, + R.raw.biometricprompt_symbol_error_to_fingerprint_portrait_bottomright, + R.raw.biometricprompt_symbol_error_to_fingerprint_portrait_topleft, + R.raw.biometricprompt_symbol_error_to_success_landscape, + R.raw.biometricprompt_symbol_error_to_success_portrait_bottomright, + R.raw.biometricprompt_symbol_error_to_success_portrait_topleft, + R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_bottomright, + R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_topleft, + R.raw.biometricprompt_symbol_fingerprint_to_success_landscape, + R.raw.biometricprompt_symbol_fingerprint_to_success_portrait_bottomright, + R.raw.biometricprompt_symbol_fingerprint_to_success_portrait_topleft + ) + } else { + cacheLottieAssetsInContext( + context, + R.raw.fingerprint_dialogue_error_to_fingerprint_lottie, + R.raw.fingerprint_dialogue_error_to_success_lottie, + R.raw.fingerprint_dialogue_fingerprint_to_error_lottie, + R.raw.fingerprint_dialogue_fingerprint_to_success_lottie + ) + } + } + override fun onFoldUpdated(isFolded: Boolean) { isDeviceFolded = isFolded } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt index b3b6fa25c9b2..d6ad4da04dbe 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt @@ -24,14 +24,15 @@ import android.graphics.drawable.AnimatedVectorDrawable import android.graphics.drawable.Drawable import android.util.Log import com.airbnb.lottie.LottieAnimationView +import com.airbnb.lottie.LottieCompositionFactory import com.android.systemui.biometrics.AuthBiometricView.BiometricState private const val TAG = "AuthIconController" /** Controller for animating the BiometricPrompt icon/affordance. */ abstract class AuthIconController( - protected val context: Context, - protected val iconView: LottieAnimationView + protected val context: Context, + protected val iconView: LottieAnimationView ) : Animatable2.AnimationCallback() { /** If this controller should ignore events and pause. */ @@ -94,4 +95,12 @@ abstract class AuthIconController( open fun handleAnimationEnd(drawable: Drawable) {} open fun onConfigurationChanged(newConfig: Configuration) {} + + // TODO(b/251476085): Migrate this to an extension at the appropriate level? + /** Load the given [rawResources] immediately so they are cached for use in the [context]. */ + protected fun cacheLottieAssetsInContext(context: Context, vararg rawResources: Int) { + for (res in rawResources) { + LottieCompositionFactory.fromRawRes(context, res) + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java new file mode 100644 index 000000000000..826253947ce1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.common.ui.view; + +import android.annotation.Nullable; +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.SeekBar; + +import com.android.systemui.R; + +/** + * The layout contains a seekbar whose progress could be modified + * through the icons on two ends of the seekbar. + */ +public class SeekBarWithIconButtonsView extends LinearLayout { + + private static final int DEFAULT_SEEKBAR_MAX = 6; + private static final int DEFAULT_SEEKBAR_PROGRESS = 0; + + private ViewGroup mIconStartFrame; + private ViewGroup mIconEndFrame; + private ImageView mIconStart; + private ImageView mIconEnd; + private SeekBar mSeekbar; + + private SeekBarChangeListener mSeekBarListener = new SeekBarChangeListener(); + + public SeekBarWithIconButtonsView(Context context) { + this(context, null); + } + + public SeekBarWithIconButtonsView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SeekBarWithIconButtonsView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public SeekBarWithIconButtonsView(Context context, + AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + + LayoutInflater.from(context).inflate( + R.layout.seekbar_with_icon_buttons, this, /* attachToRoot= */ true); + + mIconStartFrame = findViewById(R.id.icon_start_frame); + mIconEndFrame = findViewById(R.id.icon_end_frame); + mIconStart = findViewById(R.id.icon_start); + mIconEnd = findViewById(R.id.icon_end); + mSeekbar = findViewById(R.id.seekbar); + + if (attrs != null) { + TypedArray typedArray = context.obtainStyledAttributes( + attrs, + R.styleable.SeekBarWithIconButtonsView_Layout, + defStyleAttr, defStyleRes + ); + int max = typedArray.getInt( + R.styleable.SeekBarWithIconButtonsView_Layout_max, DEFAULT_SEEKBAR_MAX); + int progress = typedArray.getInt( + R.styleable.SeekBarWithIconButtonsView_Layout_progress, + DEFAULT_SEEKBAR_PROGRESS); + mSeekbar.setMax(max); + setProgress(progress); + + int iconStartFrameContentDescriptionId = typedArray.getResourceId( + R.styleable.SeekBarWithIconButtonsView_Layout_iconStartContentDescription, + /* defValue= */ 0); + int iconEndFrameContentDescriptionId = typedArray.getResourceId( + R.styleable.SeekBarWithIconButtonsView_Layout_iconEndContentDescription, + /* defValue= */ 0); + if (iconStartFrameContentDescriptionId != 0) { + final String contentDescription = + context.getString(iconStartFrameContentDescriptionId); + mIconStartFrame.setContentDescription(contentDescription); + } + if (iconEndFrameContentDescriptionId != 0) { + final String contentDescription = + context.getString(iconEndFrameContentDescriptionId); + mIconEndFrame.setContentDescription(contentDescription); + } + + typedArray.recycle(); + } else { + mSeekbar.setMax(DEFAULT_SEEKBAR_MAX); + setProgress(DEFAULT_SEEKBAR_PROGRESS); + } + + mSeekbar.setOnSeekBarChangeListener(mSeekBarListener); + + mIconStart.setOnClickListener((view) -> { + final int progress = mSeekbar.getProgress(); + if (progress > 0) { + mSeekbar.setProgress(progress - 1); + setIconViewAndFrameEnabled(mIconStart, mSeekbar.getProgress() > 0); + } + }); + + mIconEnd.setOnClickListener((view) -> { + final int progress = mSeekbar.getProgress(); + if (progress < mSeekbar.getMax()) { + mSeekbar.setProgress(progress + 1); + setIconViewAndFrameEnabled(mIconEnd, mSeekbar.getProgress() < mSeekbar.getMax()); + } + }); + } + + private static void setIconViewAndFrameEnabled(View iconView, boolean enabled) { + iconView.setEnabled(enabled); + final ViewGroup iconFrame = (ViewGroup) iconView.getParent(); + iconFrame.setEnabled(enabled); + } + + /** + * Sets a onSeekbarChangeListener to the seekbar in the layout. + * We update the Start Icon and End Icon if needed when the seekbar progress is changed. + */ + public void setOnSeekBarChangeListener( + @Nullable SeekBar.OnSeekBarChangeListener onSeekBarChangeListener) { + mSeekBarListener.setOnSeekBarChangeListener(onSeekBarChangeListener); + } + + /** + * Start and End icons might need to be updated when there is a change in seekbar progress. + * Icon Start will need to be enabled when the seekbar progress is larger than 0. + * Icon End will need to be enabled when the seekbar progress is less than Max. + */ + private void updateIconViewIfNeeded(int progress) { + setIconViewAndFrameEnabled(mIconStart, progress > 0); + setIconViewAndFrameEnabled(mIconEnd, progress < mSeekbar.getMax()); + } + + /** + * Sets max to the seekbar in the layout. + */ + public void setMax(int max) { + mSeekbar.setMax(max); + } + + /** + * Sets progress to the seekbar in the layout. + * If the progress is smaller than or equals to 0, the IconStart will be disabled. If the + * progress is larger than or equals to Max, the IconEnd will be disabled. The seekbar progress + * will be constrained in {@link SeekBar}. + */ + public void setProgress(int progress) { + mSeekbar.setProgress(progress); + updateIconViewIfNeeded(progress); + } + + private class SeekBarChangeListener implements SeekBar.OnSeekBarChangeListener { + private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = null; + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (mOnSeekBarChangeListener != null) { + mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser); + } + updateIconViewIfNeeded(progress); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + if (mOnSeekBarChangeListener != null) { + mOnSeekBarChangeListener.onStartTrackingTouch(seekBar); + } + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + if (mOnSeekBarChangeListener != null) { + mOnSeekBarChangeListener.onStopTrackingTouch(seekBar); + } + } + + void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) { + mOnSeekBarChangeListener = listener; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt index 6af8e73c8d25..d949d1119222 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt @@ -44,12 +44,15 @@ import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.controls.ui.ControlsUiControllerImpl import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tiles.DeviceControlsTile import dagger.Binds import dagger.BindsOptionalOf import dagger.Module import dagger.Provides import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap +import dagger.multibindings.StringKey /** * Module for injecting classes in `com.android.systemui.controls`- @@ -149,4 +152,9 @@ abstract class ControlsModule { @IntoMap @ClassKey(ControlsActivity::class) abstract fun provideControlsActivity(activity: ControlsActivity): Activity + + @Binds + @IntoMap + @StringKey(DeviceControlsTile.TILE_SPEC) + abstract fun bindDeviceControlsTile(controlsTile: DeviceControlsTile): QSTileImpl<*> } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index fd690dfd5dfa..03a1dc068d3d 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -27,6 +27,7 @@ import androidx.annotation.Nullable; import com.android.internal.logging.UiEventLogger; import com.android.keyguard.KeyguardViewController; +import com.android.systemui.battery.BatterySaverModule; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; @@ -40,6 +41,7 @@ import com.android.systemui.qs.dagger.QSModule; import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsImplementation; +import com.android.systemui.rotationlock.RotationLockModule; import com.android.systemui.screenshot.ReferenceScreenshotModule; import com.android.systemui.shade.NotificationShadeWindowControllerImpl; import com.android.systemui.shade.ShadeController; @@ -92,11 +94,13 @@ import dagger.Provides; */ @Module(includes = { AospPolicyModule.class, + BatterySaverModule.class, GestureModule.class, MediaModule.class, PowerModule.class, QSModule.class, ReferenceScreenshotModule.class, + RotationLockModule.class, StartCentralSurfacesModule.class, VolumeModule.class }) diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 68f4dbe53500..625a02801392 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -35,6 +35,8 @@ import com.android.systemui.unfold.FoldStateLogger; import com.android.systemui.unfold.FoldStateLoggingProvider; import com.android.systemui.unfold.SysUIUnfoldComponent; import com.android.systemui.unfold.UnfoldLatencyTracker; +import com.android.systemui.unfold.UnfoldTransitionProgressProvider; +import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder; import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider; import com.android.wm.shell.TaskViewFactory; import com.android.wm.shell.back.BackAnimation; @@ -137,6 +139,10 @@ public interface SysUIComponent { getUnfoldLatencyTracker().init(); getFoldStateLoggingProvider().ifPresent(FoldStateLoggingProvider::init); getFoldStateLogger().ifPresent(FoldStateLogger::init); + getUnfoldTransitionProgressProvider().ifPresent((progressProvider) -> + getUnfoldTransitionProgressForwarder().ifPresent((forwarder) -> + progressProvider.addCallback(forwarder) + )); } /** @@ -164,6 +170,18 @@ public interface SysUIComponent { UnfoldLatencyTracker getUnfoldLatencyTracker(); /** + * Creates a UnfoldTransitionProgressProvider. + */ + @SysUISingleton + Optional<UnfoldTransitionProgressProvider> getUnfoldTransitionProgressProvider(); + + /** + * Creates a UnfoldTransitionProgressForwarder. + */ + @SysUISingleton + Optional<UnfoldTransitionProgressForwarder> getUnfoldTransitionProgressForwarder(); + + /** * Creates a FoldStateLoggingProvider. */ @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemPropertiesFlagsModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemPropertiesFlagsModule.kt new file mode 100644 index 000000000000..c6f833ba2cfd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemPropertiesFlagsModule.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dagger + +import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags +import dagger.Module +import dagger.Provides + +/** A module which provides access to the default [SystemUiSystemPropertiesFlags.FlagResolver] */ +@Module +object SystemPropertiesFlagsModule { + /** provide the default FlagResolver. */ + @Provides + fun provideFlagResolver(): SystemUiSystemPropertiesFlags.FlagResolver = + SystemUiSystemPropertiesFlags.getResolver() +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index cb7c765d0549..bddd8a7c147c 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -55,7 +55,6 @@ import com.android.systemui.theme.ThemeOverlayController import com.android.systemui.toast.ToastUI import com.android.systemui.usb.StorageNotification import com.android.systemui.util.NotificationChannels -import com.android.systemui.util.leak.GarbageMonitor import com.android.systemui.volume.VolumeUI import com.android.systemui.wmshell.WMShell import dagger.Binds @@ -107,12 +106,6 @@ abstract class SystemUICoreStartableModule { @ClassKey(FsiChromeViewBinder::class) abstract fun bindFsiChromeWindowBinder(sysui: FsiChromeViewBinder): CoreStartable - /** Inject into GarbageMonitor.Service. */ - @Binds - @IntoMap - @ClassKey(GarbageMonitor::class) - abstract fun bindGarbageMonitorService(sysui: GarbageMonitor.Service): CoreStartable - /** Inject into GlobalActionsComponent. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 6274a26682f4..60fccef3ef57 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -28,6 +28,7 @@ import com.android.keyguard.dagger.ClockRegistryModule; import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.BootCompleteCache; import com.android.systemui.BootCompleteCacheImpl; +import com.android.systemui.accessibility.AccessibilityModule; import com.android.systemui.appops.dagger.AppOpsModule; import com.android.systemui.assist.AssistModule; import com.android.systemui.biometrics.AlternateUdfpsTouchProvider; @@ -57,10 +58,12 @@ import com.android.systemui.people.PeopleModule; import com.android.systemui.plugins.BcSmartspaceConfigPlugin; import com.android.systemui.plugins.BcSmartspaceDataPlugin; import com.android.systemui.privacy.PrivacyModule; +import com.android.systemui.qrcodescanner.dagger.QRCodeScannerModule; import com.android.systemui.qs.FgsManagerController; import com.android.systemui.qs.FgsManagerControllerImpl; import com.android.systemui.qs.footer.dagger.FooterActionsModule; import com.android.systemui.recents.Recents; +import com.android.systemui.screenrecord.ScreenRecordModule; import com.android.systemui.screenshot.dagger.ScreenshotModule; import com.android.systemui.security.data.repository.SecurityRepositoryModule; import com.android.systemui.settings.DisplayTracker; @@ -70,6 +73,7 @@ import com.android.systemui.smartspace.dagger.SmartspaceModule; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationShadeWindowController; +import com.android.systemui.statusbar.connectivity.ConnectivityModule; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; @@ -85,6 +89,7 @@ import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.PolicyModule; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule; import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule; @@ -97,6 +102,7 @@ import com.android.systemui.user.UserModule; import com.android.systemui.util.concurrency.SysUIConcurrencyModule; import com.android.systemui.util.dagger.UtilModule; import com.android.systemui.util.kotlin.CoroutinesModule; +import com.android.systemui.util.leak.GarbageMonitorModule; import com.android.systemui.util.sensors.SensorModule; import com.android.systemui.util.settings.SettingsUtilModule; import com.android.systemui.util.time.SystemClock; @@ -126,6 +132,7 @@ import dagger.Provides; * may not appreciate that. */ @Module(includes = { + AccessibilityModule.class, AppOpsModule.class, AssistModule.class, BiometricsModule.class, @@ -133,24 +140,30 @@ import dagger.Provides; ClipboardOverlayModule.class, ClockInfoModule.class, ClockRegistryModule.class, + ConnectivityModule.class, CoroutinesModule.class, DreamModule.class, ControlsModule.class, DemoModeModule.class, FalsingModule.class, FlagsModule.class, + SystemPropertiesFlagsModule.class, FooterActionsModule.class, + GarbageMonitorModule.class, LogModule.class, MediaProjectionModule.class, MotionToolModule.class, PeopleHubModule.class, PeopleModule.class, PluginModule.class, + PolicyModule.class, PrivacyModule.class, + QRCodeScannerModule.class, ScreenshotModule.class, SensorModule.class, MultiUserUtilsModule.class, SecurityRepositoryModule.class, + ScreenRecordModule.class, SettingsUtilModule.class, SmartRepliesInflationModule.class, SmartspaceModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java index 102f2082ebd1..055cd52b23d6 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java @@ -16,19 +16,23 @@ package com.android.systemui.dreams; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; + import android.util.Log; import com.android.systemui.CoreStartable; import com.android.systemui.dreams.callbacks.DreamStatusBarStateCallback; import com.android.systemui.dreams.conditions.DreamCondition; import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.condition.ConditionalCoreStartable; import javax.inject.Inject; +import javax.inject.Named; /** * A {@link CoreStartable} to retain a monitor for tracking dreaming. */ -public class DreamMonitor implements CoreStartable { +public class DreamMonitor extends ConditionalCoreStartable { private static final String TAG = "DreamMonitor"; // We retain a reference to the monitor so it is not garbage-collected. @@ -39,14 +43,17 @@ public class DreamMonitor implements CoreStartable { @Inject public DreamMonitor(Monitor monitor, DreamCondition dreamCondition, + @Named(DREAM_PRETEXT_MONITOR) Monitor pretextMonitor, DreamStatusBarStateCallback callback) { + super(pretextMonitor); mConditionMonitor = monitor; mDreamCondition = dreamCondition; mCallback = callback; } + @Override - public void start() { + protected void onStart() { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "started"); } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java index 87c5f51ce13a..a2dcdf52ad3c 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java @@ -17,6 +17,7 @@ package com.android.systemui.dreams; import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_SERVICE_COMPONENT; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -33,8 +34,9 @@ import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; import android.util.Log; -import com.android.systemui.CoreStartable; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.condition.ConditionalCoreStartable; import javax.inject.Inject; import javax.inject.Named; @@ -43,7 +45,7 @@ import javax.inject.Named; * {@link DreamOverlayRegistrant} is responsible for telling system server that SystemUI should be * the designated dream overlay component. */ -public class DreamOverlayRegistrant implements CoreStartable { +public class DreamOverlayRegistrant extends ConditionalCoreStartable { private static final String TAG = "DreamOverlayRegistrant"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final IDreamManager mDreamManager; @@ -102,7 +104,9 @@ public class DreamOverlayRegistrant implements CoreStartable { @Inject public DreamOverlayRegistrant(Context context, @Main Resources resources, - @Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName dreamOverlayServiceComponent) { + @Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName dreamOverlayServiceComponent, + @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) { + super(monitor); mContext = context; mResources = resources; mDreamManager = IDreamManager.Stub.asInterface( @@ -111,7 +115,7 @@ public class DreamOverlayRegistrant implements CoreStartable { } @Override - public void start() { + protected void onStart() { final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); filter.addDataSchemeSpecificPart(mOverlayServiceComponent.getPackageName(), diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java index ee2f1af6a99b..244212b45790 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java @@ -16,27 +16,31 @@ package com.android.systemui.dreams.complication; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; + import android.database.ContentObserver; import android.os.UserHandle; import android.provider.Settings; import com.android.settingslib.dream.DreamBackend; -import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.condition.ConditionalCoreStartable; import com.android.systemui.util.settings.SecureSettings; import java.util.concurrent.Executor; import javax.inject.Inject; +import javax.inject.Named; /** * {@link ComplicationTypesUpdater} observes the state of available complication types set by the * user, and pushes updates to {@link DreamOverlayStateController}. */ @SysUISingleton -public class ComplicationTypesUpdater implements CoreStartable { +public class ComplicationTypesUpdater extends ConditionalCoreStartable { private final DreamBackend mDreamBackend; private final Executor mExecutor; private final SecureSettings mSecureSettings; @@ -48,7 +52,9 @@ public class ComplicationTypesUpdater implements CoreStartable { DreamBackend dreamBackend, @Main Executor executor, SecureSettings secureSettings, - DreamOverlayStateController dreamOverlayStateController) { + DreamOverlayStateController dreamOverlayStateController, + @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) { + super(monitor); mDreamBackend = dreamBackend; mExecutor = executor; mSecureSettings = secureSettings; @@ -56,7 +62,7 @@ public class ComplicationTypesUpdater implements CoreStartable { } @Override - public void start() { + public void onStart() { final ContentObserver settingsObserver = new ContentObserver(null /*handler*/) { @Override public void onChange(boolean selfChange) { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java index 77e1fc91e6ee..bb1e6e2ef06d 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java @@ -18,11 +18,14 @@ package com.android.systemui.dreams.complication; import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW; import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; import android.view.View; import com.android.systemui.CoreStartable; import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.condition.ConditionalCoreStartable; import javax.inject.Inject; import javax.inject.Named; @@ -60,7 +63,7 @@ public class DreamClockTimeComplication implements Complication { * {@link CoreStartable} responsible for registering {@link DreamClockTimeComplication} with * SystemUI. */ - public static class Registrant implements CoreStartable { + public static class Registrant extends ConditionalCoreStartable { private final DreamOverlayStateController mDreamOverlayStateController; private final DreamClockTimeComplication mComplication; @@ -70,13 +73,15 @@ public class DreamClockTimeComplication implements Complication { @Inject public Registrant( DreamOverlayStateController dreamOverlayStateController, - DreamClockTimeComplication dreamClockTimeComplication) { + DreamClockTimeComplication dreamClockTimeComplication, + @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) { + super(monitor); mDreamOverlayStateController = dreamOverlayStateController; mComplication = dreamClockTimeComplication; } @Override - public void start() { + public void onStart() { mDreamOverlayStateController.addComplication(mComplication); } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java index 1065b94508f8..7f395d863c3f 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java @@ -21,6 +21,7 @@ import static com.android.systemui.controls.dagger.ControlsComponent.Visibility. import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.UNAVAILABLE; import static com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent.DreamHomeControlsModule.DREAM_HOME_CONTROLS_CHIP_VIEW; import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; import android.content.Context; import android.content.Intent; @@ -42,7 +43,9 @@ import com.android.systemui.controls.ui.ControlsUiController; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.shared.condition.Monitor; import com.android.systemui.util.ViewController; +import com.android.systemui.util.condition.ConditionalCoreStartable; import java.util.List; @@ -75,7 +78,7 @@ public class DreamHomeControlsComplication implements Complication { /** * {@link CoreStartable} for registering the complication with SystemUI on startup. */ - public static class Registrant implements CoreStartable { + public static class Registrant extends ConditionalCoreStartable { private final DreamHomeControlsComplication mComplication; private final DreamOverlayStateController mDreamOverlayStateController; private final ControlsComponent mControlsComponent; @@ -105,14 +108,16 @@ public class DreamHomeControlsComplication implements Complication { @Inject public Registrant(DreamHomeControlsComplication complication, DreamOverlayStateController dreamOverlayStateController, - ControlsComponent controlsComponent) { + ControlsComponent controlsComponent, + @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) { + super(monitor); mComplication = complication; mControlsComponent = controlsComponent; mDreamOverlayStateController = dreamOverlayStateController; } @Override - public void start() { + public void onStart() { mControlsComponent.getControlsListingController().ifPresent( c -> c.addCallback(mControlsCallback)); mDreamOverlayStateController.addCallback(mOverlayStateCallback); diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java index c3aaf0cbf2d7..e39073bb6711 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java @@ -17,6 +17,7 @@ package com.android.systemui.dreams.complication; import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_SMARTSPACE_LAYOUT_PARAMS; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; import android.content.Context; import android.os.Parcelable; @@ -28,6 +29,8 @@ import com.android.systemui.CoreStartable; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.smartspace.DreamSmartspaceController; import com.android.systemui.plugins.BcSmartspaceDataPlugin; +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.condition.ConditionalCoreStartable; import java.util.List; @@ -61,7 +64,7 @@ public class SmartSpaceComplication implements Complication { * {@link CoreStartable} responsbile for registering {@link SmartSpaceComplication} with * SystemUI. */ - public static class Registrant implements CoreStartable { + public static class Registrant extends ConditionalCoreStartable { private final DreamSmartspaceController mSmartSpaceController; private final DreamOverlayStateController mDreamOverlayStateController; private final SmartSpaceComplication mComplication; @@ -81,14 +84,16 @@ public class SmartSpaceComplication implements Complication { public Registrant( DreamOverlayStateController dreamOverlayStateController, SmartSpaceComplication smartSpaceComplication, - DreamSmartspaceController smartSpaceController) { + DreamSmartspaceController smartSpaceController, + @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) { + super(monitor); mDreamOverlayStateController = dreamOverlayStateController; mComplication = smartSpaceComplication; mSmartSpaceController = smartSpaceController; } @Override - public void start() { + public void onStart() { mDreamOverlayStateController.addCallback(new DreamOverlayStateController.Callback() { @Override public void onStateChanged() { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java index 0ab8c8e42b03..88c02b8aa790 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java @@ -29,13 +29,20 @@ import com.android.systemui.dreams.DreamOverlayNotificationCountProvider; import com.android.systemui.dreams.DreamOverlayService; import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule; import com.android.systemui.dreams.touch.scrim.dagger.ScrimModule; +import com.android.systemui.process.condition.UserProcessCondition; +import com.android.systemui.shared.condition.Condition; +import com.android.systemui.shared.condition.Monitor; import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Executor; import javax.inject.Named; +import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.IntoSet; /** * Dagger Module providing Dream-related functionality. @@ -54,6 +61,8 @@ public interface DreamModule { String DREAM_OVERLAY_ENABLED = "dream_overlay_enabled"; String DREAM_SUPPORTED = "dream_supported"; + String DREAM_PRETEXT_CONDITIONS = "dream_pretext_conditions"; + String DREAM_PRETEXT_MONITOR = "dream_prtext_monitor"; /** * Provides the dream component @@ -112,4 +121,19 @@ public interface DreamModule { static boolean providesDreamSupported(@Main Resources resources) { return resources.getBoolean(com.android.internal.R.bool.config_dreamsSupported); } + + /** */ + @Binds + @IntoSet + @Named(DREAM_PRETEXT_CONDITIONS) + Condition bindsUserProcessCondition(UserProcessCondition condition); + + /** */ + @Provides + @Named(DREAM_PRETEXT_MONITOR) + static Monitor providesDockerPretextMonitor( + @Main Executor executor, + @Named(DREAM_PRETEXT_CONDITIONS) Set<Condition> pretextConditions) { + return new Monitor(executor, pretextConditions); + } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java index 4bac69776319..58fe0940b7fb 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java @@ -40,7 +40,6 @@ import androidx.annotation.Nullable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.util.settings.GlobalSettings; -import com.android.systemui.util.settings.SecureSettings; import org.jetbrains.annotations.NotNull; @@ -74,7 +73,6 @@ public class FeatureFlagsDebug implements FeatureFlags { private final FlagManager mFlagManager; private final Context mContext; private final GlobalSettings mGlobalSettings; - private final SecureSettings mSecureSettings; private final Resources mResources; private final SystemPropertiesHelper mSystemProperties; private final ServerFlagReader mServerFlagReader; @@ -87,8 +85,9 @@ public class FeatureFlagsDebug implements FeatureFlags { private final ServerFlagReader.ChangeListener mOnPropertiesChanged = new ServerFlagReader.ChangeListener() { @Override - public void onChange() { - mRestarter.restartSystemUI(); + public void onChange(Flag<?> flag) { + mRestarter.restartSystemUI( + "Server flag change: " + flag.getNamespace() + "." + flag.getName()); } }; @@ -97,7 +96,6 @@ public class FeatureFlagsDebug implements FeatureFlags { FlagManager flagManager, Context context, GlobalSettings globalSettings, - SecureSettings secureSettings, SystemPropertiesHelper systemProperties, @Main Resources resources, ServerFlagReader serverFlagReader, @@ -106,7 +104,6 @@ public class FeatureFlagsDebug implements FeatureFlags { mFlagManager = flagManager; mContext = context; mGlobalSettings = globalSettings; - mSecureSettings = secureSettings; mResources = resources; mSystemProperties = systemProperties; mServerFlagReader = serverFlagReader; @@ -119,7 +116,8 @@ public class FeatureFlagsDebug implements FeatureFlags { IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_SET_FLAG); filter.addAction(ACTION_GET_FLAGS); - mFlagManager.setOnSettingsChangedAction(this::restartSystemUI); + mFlagManager.setOnSettingsChangedAction( + suppressRestart -> restartSystemUI(suppressRestart, "Settings changed")); mFlagManager.setClearCacheAction(this::removeFromCache); mContext.registerReceiver(mReceiver, filter, null, null, Context.RECEIVER_EXPORTED_UNAUDITED); @@ -233,6 +231,10 @@ public class FeatureFlagsDebug implements FeatureFlags { Boolean result = readBooleanFlagOverride(flag.getName()); if (result == null) { result = readBooleanFlagOverride(flag.getId()); + if (result != null) { + // Move overrides from id to name + setFlagValueInternal(flag.getName(), result, BooleanFlagSerializer.INSTANCE); + } } boolean hasServerOverride = mServerFlagReader.hasOverride( flag.getNamespace(), flag.getName()); @@ -305,25 +307,38 @@ public class FeatureFlagsDebug implements FeatureFlags { requireNonNull(value, "Cannot set a null value"); T currentValue = readFlagValueInternal(name, serializer); if (Objects.equals(currentValue, value)) { - Log.i(TAG, "Flag id " + name + " is already " + value); + Log.i(TAG, "Flag \"" + name + "\" is already " + value); return; } + setFlagValueInternal(name, value, serializer); + Log.i(TAG, "Set flag \"" + name + "\" to " + value); + removeFromCache(name); + mFlagManager.dispatchListenersAndMaybeRestart( + name, + suppressRestart -> restartSystemUI( + suppressRestart, "Flag \"" + name + "\" changed to " + value)); + } + + private <T> void setFlagValueInternal( + String name, @NonNull T value, FlagSerializer<T> serializer) { final String data = serializer.toSettingsData(value); if (data == null) { - Log.w(TAG, "Failed to set id " + name + " to " + value); + Log.w(TAG, "Failed to set flag " + name + " to " + value); return; } mGlobalSettings.putStringForUser(mFlagManager.nameToSettingsKey(name), data, UserHandle.USER_CURRENT); - Log.i(TAG, "Set id " + name + " to " + value); - removeFromCache(name); - mFlagManager.dispatchListenersAndMaybeRestart(name, this::restartSystemUI); } <T> void eraseFlag(Flag<T> flag) { if (flag instanceof SysPropFlag) { - mSystemProperties.erase(((SysPropFlag<T>) flag).getName()); - dispatchListenersAndMaybeRestart(flag.getName(), this::restartAndroid); + mSystemProperties.erase(flag.getName()); + dispatchListenersAndMaybeRestart( + flag.getName(), + suppressRestart -> restartSystemUI( + suppressRestart, + "SysProp Flag \"" + flag.getNamespace() + "." + + flag.getName() + "\" reset to default.")); } else { eraseFlag(flag.getName()); } @@ -333,7 +348,10 @@ public class FeatureFlagsDebug implements FeatureFlags { private void eraseFlag(String name) { eraseInternal(name); removeFromCache(name); - dispatchListenersAndMaybeRestart(name, this::restartSystemUI); + dispatchListenersAndMaybeRestart( + name, + suppressRestart -> restartSystemUI( + suppressRestart, "Flag \"" + name + "\" reset to default")); } private void dispatchListenersAndMaybeRestart(String name, Consumer<Boolean> restartAction) { @@ -367,20 +385,20 @@ public class FeatureFlagsDebug implements FeatureFlags { mFlagManager.removeListener(listener); } - private void restartSystemUI(boolean requestSuppress) { + private void restartSystemUI(boolean requestSuppress, String reason) { if (requestSuppress) { Log.i(TAG, "SystemUI Restart Suppressed"); return; } - mRestarter.restartSystemUI(); + mRestarter.restartSystemUI(reason); } - private void restartAndroid(boolean requestSuppress) { + private void restartAndroid(boolean requestSuppress, String reason) { if (requestSuppress) { Log.i(TAG, "Android Restart Suppressed"); return; } - mRestarter.restartAndroid(); + mRestarter.restartAndroid(reason); } void setBooleanFlagInternal(Flag<?> flag, boolean value) { @@ -391,8 +409,11 @@ public class FeatureFlagsDebug implements FeatureFlags { } else if (flag instanceof SysPropBooleanFlag) { // Store SysProp flags in SystemProperties where they can read by outside parties. mSystemProperties.setBoolean(((SysPropBooleanFlag) flag).getName(), value); - dispatchListenersAndMaybeRestart(flag.getName(), - FeatureFlagsDebug.this::restartAndroid); + dispatchListenersAndMaybeRestart( + flag.getName(), + suppressRestart -> restartSystemUI( + suppressRestart, + "Flag \"" + flag.getName() + "\" changed to " + value)); } else { throw new IllegalArgumentException("Unknown flag type"); } diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugRestarter.kt index 069e6127aa30..a6956a443e46 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugRestarter.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugRestarter.kt @@ -29,6 +29,7 @@ constructor( ) : Restarter { private var androidRestartRequested = false + private var pendingReason = "" val observer = object : WakefulnessLifecycle.Observer { @@ -38,18 +39,20 @@ constructor( } } - override fun restartSystemUI() { + override fun restartSystemUI(reason: String) { Log.d(FeatureFlagsDebug.TAG, "SystemUI Restart requested. Restarting on next screen off.") - scheduleRestart() + Log.i(FeatureFlagsDebug.TAG, reason) + scheduleRestart(reason) } - override fun restartAndroid() { + override fun restartAndroid(reason: String) { Log.d(FeatureFlagsDebug.TAG, "Android Restart requested. Restarting on next screen off.") androidRestartRequested = true - scheduleRestart() + scheduleRestart(reason) } - fun scheduleRestart() { + fun scheduleRestart(reason: String) { + pendingReason = reason if (wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_ASLEEP) { restartNow() } else { @@ -59,9 +62,9 @@ constructor( private fun restartNow() { if (androidRestartRequested) { - systemExitRestarter.restartAndroid() + systemExitRestarter.restartAndroid(pendingReason) } else { - systemExitRestarter.restartSystemUI() + systemExitRestarter.restartSystemUI(pendingReason) } } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java index 7e1423706fc9..9859ff6b4917 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java @@ -57,8 +57,9 @@ public class FeatureFlagsRelease implements FeatureFlags { private final ServerFlagReader.ChangeListener mOnPropertiesChanged = new ServerFlagReader.ChangeListener() { @Override - public void onChange() { - mRestarter.restartSystemUI(); + public void onChange(Flag<?> flag) { + mRestarter.restartSystemUI( + "Server flag change: " + flag.getNamespace() + "." + flag.getName()); } }; diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseRestarter.kt index 7ff3876f5d4e..c08266caf147 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseRestarter.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseRestarter.kt @@ -36,41 +36,43 @@ constructor( ) : Restarter { var listenersAdded = false var pendingRestart: Runnable? = null + private var pendingReason = "" var androidRestartRequested = false val observer = object : WakefulnessLifecycle.Observer { override fun onFinishedGoingToSleep() { - scheduleRestart() + scheduleRestart(pendingReason) } } val batteryCallback = object : BatteryController.BatteryStateChangeCallback { override fun onBatteryLevelChanged(level: Int, pluggedIn: Boolean, charging: Boolean) { - scheduleRestart() + scheduleRestart(pendingReason) } } - override fun restartSystemUI() { + override fun restartSystemUI(reason: String) { Log.d( FeatureFlagsDebug.TAG, "SystemUI Restart requested. Restarting when plugged in and idle." ) - scheduleRestart() + scheduleRestart(reason) } - override fun restartAndroid() { + override fun restartAndroid(reason: String) { Log.d( FeatureFlagsDebug.TAG, "Android Restart requested. Restarting when plugged in and idle." ) androidRestartRequested = true - scheduleRestart() + scheduleRestart(reason) } - private fun scheduleRestart() { + private fun scheduleRestart(reason: String) { // Don't bother adding listeners twice. + pendingReason = reason if (!listenersAdded) { listenersAdded = true wakefulnessLifecycle.addObserver(observer) @@ -91,9 +93,9 @@ constructor( private fun restartNow() { Log.d(FeatureFlagsRelease.TAG, "Restarting due to systemui flag change") if (androidRestartRequested) { - systemExitRestarter.restartAndroid() + systemExitRestarter.restartAndroid(pendingReason) } else { - systemExitRestarter.restartSystemUI() + systemExitRestarter.restartSystemUI(pendingReason) } } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 007892819b29..ff3e7298de56 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -100,7 +100,7 @@ object Flags { // TODO(b/260335638): Tracking Bug @JvmField val NOTIFICATION_INLINE_REPLY_ANIMATION = - unreleasedFlag(174148361, "notification_inline_reply_animation", teamfood = true) + releasedFlag(174148361, "notification_inline_reply_animation") val FILTER_UNSEEN_NOTIFS_ON_KEYGUARD = releasedFlag(254647461, "filter_unseen_notifs_on_keyguard", teamfood = true) @@ -515,6 +515,11 @@ object Flags { @JvmField val SCREENSHOT_DETECTION = unreleasedFlag(1303, "screenshot_detection", teamfood = true) + // TODO(b/268484562): Tracking bug + @JvmField + val SCREENSHOT_METADATA_REFACTOR = + unreleasedFlag(1305, "screenshot_metadata_refactor", teamfood = true) + // 1400 - columbus // TODO(b/254512756): Tracking Bug val QUICK_TAP_IN_PCC = releasedFlag(1400, "quick_tap_in_pcc") @@ -573,6 +578,12 @@ object Flags { val CONTROLS_MANAGEMENT_NEW_FLOWS = unreleasedFlag(2002, "controls_management_new_flows", teamfood = true) + // Enables removing app from Home control panel as a part of a new flow + // TODO(b/269132640): Tracking Bug + @JvmField + val APP_PANELS_REMOVE_APPS_ALLOWED = + unreleasedFlag(2003, "app_panels_remove_apps_allowed", teamfood = false) + // 2100 - Falsing Manager @JvmField val FALSING_FOR_LONG_TAPS = releasedFlag(2100, "falsing_for_long_taps") diff --git a/packages/SystemUI/src/com/android/systemui/flags/Restarter.kt b/packages/SystemUI/src/com/android/systemui/flags/Restarter.kt index ce8b821b1182..9c677950d650 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Restarter.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Restarter.kt @@ -16,7 +16,7 @@ package com.android.systemui.flags interface Restarter { - fun restartSystemUI() + fun restartSystemUI(reason: String) - fun restartAndroid() + fun restartAndroid(reason: String) } diff --git a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt index a02b795f074e..e225b10d4e52 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt @@ -17,8 +17,10 @@ package com.android.systemui.flags import android.provider.DeviceConfig +import android.util.Log import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.TestHarness import com.android.systemui.util.DeviceConfigProxy import dagger.Module import dagger.Provides @@ -35,21 +37,27 @@ interface ServerFlagReader { fun listenForChanges(values: Collection<Flag<*>>, listener: ChangeListener) interface ChangeListener { - fun onChange() + fun onChange(flag: Flag<*>) } } class ServerFlagReaderImpl @Inject constructor( private val namespace: String, private val deviceConfig: DeviceConfigProxy, - @Background private val executor: Executor + @Background private val executor: Executor, + @TestHarness private val isTestHarness: Boolean ) : ServerFlagReader { + private val TAG = "ServerFlagReader" + private val listeners = mutableListOf<Pair<ServerFlagReader.ChangeListener, Collection<Flag<*>>>>() private val onPropertiesChangedListener = object : DeviceConfig.OnPropertiesChangedListener { override fun onPropertiesChanged(properties: DeviceConfig.Properties) { + if (isTestHarness) { + Log.w(TAG, "Ignore server flag changes in Test Harness mode.") + } if (properties.namespace != namespace) { return } @@ -59,7 +67,7 @@ class ServerFlagReaderImpl @Inject constructor( propLoop@ for (propName in properties.keyset) { for (flag in flags) { if (propName == getServerOverrideName(flag.id) || propName == flag.name) { - listener.onChange() + listener.onChange(flag) break@propLoop } } @@ -111,10 +119,11 @@ interface ServerFlagReaderModule { @SysUISingleton fun bindsReader( deviceConfig: DeviceConfigProxy, - @Background executor: Executor + @Background executor: Executor, + @TestHarness isTestHarness: Boolean ): ServerFlagReader { return ServerFlagReaderImpl( - SYSUI_NAMESPACE, deviceConfig, executor + SYSUI_NAMESPACE, deviceConfig, executor, isTestHarness ) } } @@ -139,7 +148,7 @@ class ServerFlagReaderFake : ServerFlagReader { for ((listener, flags) in listeners) { flagLoop@ for (flag in flags) { if (name == flag.name) { - listener.onChange() + listener.onChange(flag) break@flagLoop } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt index 89daa6487fbc..46e28a7d0ef2 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt @@ -16,6 +16,7 @@ package com.android.systemui.flags +import android.util.Log import com.android.internal.statusbar.IStatusBarService import javax.inject.Inject @@ -24,11 +25,13 @@ class SystemExitRestarter constructor( private val barService: IStatusBarService, ) : Restarter { - override fun restartAndroid() { + override fun restartAndroid(reason: String) { + Log.d(FeatureFlagsDebug.TAG, "Restarting Android: " + reason) barService.restart() } - override fun restartSystemUI() { + override fun restartSystemUI(reason: String) { + Log.d(FeatureFlagsDebug.TAG, "Restarting SystemUI: " + reason) System.exit(0) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt index 5a9f7752277e..c9f645dddd8d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.app.StatusBarManager +import android.app.admin.DevicePolicyManager import android.content.Context import android.content.pm.PackageManager import com.android.systemui.R @@ -27,10 +28,14 @@ import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.settings.UserTracker import dagger.Lazy import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.withContext @SysUISingleton class CameraQuickAffordanceConfig @@ -39,6 +44,9 @@ constructor( @Application private val context: Context, private val packageManager: PackageManager, private val cameraGestureHelper: Lazy<CameraGestureHelper>, + private val userTracker: UserTracker, + private val devicePolicyManager: DevicePolicyManager, + @Background private val backgroundDispatcher: CoroutineDispatcher, ) : KeyguardQuickAffordanceConfig { override val key: String @@ -79,7 +87,12 @@ constructor( return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled } - private fun isLaunchable(): Boolean { - return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) + private suspend fun isLaunchable(): Boolean { + return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) && + withContext(backgroundDispatcher) { + !devicePolicyManager.getCameraDisabled(null, userTracker.userId) && + devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId) and + DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA == 0 + } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt index d9ec3b1c2f87..6f821a2b5228 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.app.StatusBarManager +import android.app.admin.DevicePolicyManager import android.content.Context import android.content.Intent import com.android.systemui.ActivityIntentHelper @@ -29,10 +30,13 @@ import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.settings.UserTracker import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.withContext @SysUISingleton class VideoCameraQuickAffordanceConfig @@ -42,6 +46,8 @@ constructor( private val cameraIntents: CameraIntentsWrapper, private val activityIntentHelper: ActivityIntentHelper, private val userTracker: UserTracker, + private val devicePolicyManager: DevicePolicyManager, + @Background private val backgroundDispatcher: CoroutineDispatcher, ) : KeyguardQuickAffordanceConfig { private val intent: Intent by lazy { @@ -63,8 +69,8 @@ constructor( get() = R.drawable.ic_videocam override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> - get() = - flowOf( + get() = flow { + emit( if (isLaunchable()) { KeyguardQuickAffordanceConfig.LockScreenState.Visible( icon = @@ -77,6 +83,7 @@ constructor( KeyguardQuickAffordanceConfig.LockScreenState.Hidden } ) + } override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState { return if (isLaunchable()) { @@ -95,11 +102,14 @@ constructor( ) } - private fun isLaunchable(): Boolean { + private suspend fun isLaunchable(): Boolean { return activityIntentHelper.getTargetActivityInfo( intent, userTracker.userId, true, - ) != null + ) != null && + withContext(backgroundDispatcher) { + !devicePolicyManager.getCameraDisabled(null, userTracker.userId) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt index 520edef7d109..f5558a240a70 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt @@ -1343,9 +1343,9 @@ class MediaDataManager( if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) { logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId) } else if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) { - convertToResumePlayer(removed) + convertToResumePlayer(key, removed) } else if (mediaFlags.isRetainingPlayersEnabled()) { - handlePossibleRemoval(removed, notificationRemoved = true) + handlePossibleRemoval(key, removed, notificationRemoved = true) } else { notifyMediaDataRemoved(key) logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId) @@ -1359,7 +1359,7 @@ class MediaDataManager( val entry = mediaEntries.remove(key) ?: return // Clear token since the session is no longer valid val updated = entry.copy(token = null) - handlePossibleRemoval(updated) + handlePossibleRemoval(key, updated) } /** @@ -1368,8 +1368,11 @@ class MediaDataManager( * if it was removed before becoming inactive. (Assumes that [removed] was removed from * [mediaEntries] before this function was called) */ - private fun handlePossibleRemoval(removed: MediaData, notificationRemoved: Boolean = false) { - val key = removed.notificationKey!! + private fun handlePossibleRemoval( + key: String, + removed: MediaData, + notificationRemoved: Boolean = false + ) { val hasSession = removed.token != null if (hasSession && removed.semanticActions != null) { // The app was using session actions, and the session is still valid: keep player @@ -1395,13 +1398,12 @@ class MediaDataManager( "($hasSession) gone for inactive player $key" ) } - convertToResumePlayer(removed) + convertToResumePlayer(key, removed) } } /** Set the given [MediaData] as a resume state player and notify listeners */ - private fun convertToResumePlayer(data: MediaData) { - val key = data.notificationKey!! + private fun convertToResumePlayer(key: String, data: MediaData) { if (DEBUG) Log.d(TAG, "Converting $key to resume") // Move to resume key (aka package name) if that key doesn't already exist. val resumeAction = data.resumeAction?.let { getResumeMediaAction(it) } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt index b72923a5d22c..68d2c5c5f4c4 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt @@ -164,13 +164,13 @@ constructor( mediaCarouselScrollHandler.scrollToStart() } } - private var currentlyExpanded = true + + @VisibleForTesting + var currentlyExpanded = true set(value) { if (field != value) { field = value - for (player in MediaPlayerData.players()) { - player.setListening(field) - } + updateSeekbarListening(mediaCarouselScrollHandler.visibleToUser) } } @@ -259,6 +259,7 @@ constructor( executor, this::onSwipeToDismiss, this::updatePageIndicatorLocation, + this::updateSeekbarListening, this::closeGuts, falsingCollector, falsingManager, @@ -590,6 +591,17 @@ constructor( ?: mediaCarouselScrollHandler.scrollToPlayer(destIndex = mediaIndex) } } + // Check postcondition: mediaContent should have the same number of children as there + // are + // elements in mediaPlayers. + if (MediaPlayerData.players().size != mediaContent.childCount) { + Log.e( + TAG, + "Size of players list and number of views in carousel are out of sync. " + + "Players size is ${MediaPlayerData.players().size}. " + + "View count is ${mediaContent.childCount}." + ) + } } // Returns true if new player is added @@ -618,7 +630,9 @@ constructor( ) newPlayer.mediaViewHolder?.player?.setLayoutParams(lp) newPlayer.bindPlayer(data, key) - newPlayer.setListening(currentlyExpanded) + newPlayer.setListening( + mediaCarouselScrollHandler.visibleToUser && currentlyExpanded + ) MediaPlayerData.addMediaPlayer( key, data, @@ -665,17 +679,6 @@ constructor( updatePageIndicator() mediaCarouselScrollHandler.onPlayersChanged() mediaFrame.requiresRemeasuring = true - // Check postcondition: mediaContent should have the same number of children as there - // are - // elements in mediaPlayers. - if (MediaPlayerData.players().size != mediaContent.childCount) { - Log.e( - TAG, - "Size of players list and number of views in carousel are out of sync. " + - "Players size is ${MediaPlayerData.players().size}. " + - "View count is ${mediaContent.childCount}." - ) - } return existingPlayer == null } @@ -914,6 +917,13 @@ constructor( .toFloat() } + /** Update listening to seekbar. */ + private fun updateSeekbarListening(visibleToUser: Boolean) { + for (player in MediaPlayerData.players()) { + player.setListening(visibleToUser && currentlyExpanded) + } + } + /** Update the dimension of this carousel. */ private fun updateCarouselDimensions() { var width = 0 diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt index 36b2eda65fab..1ace3168780a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt @@ -57,6 +57,7 @@ class MediaCarouselScrollHandler( private val mainExecutor: DelayableExecutor, val dismissCallback: () -> Unit, private var translationChangedListener: () -> Unit, + private var seekBarUpdateListener: (visibleToUser: Boolean) -> Unit, private val closeGuts: (immediate: Boolean) -> Unit, private val falsingCollector: FalsingCollector, private val falsingManager: FalsingManager, @@ -177,6 +178,12 @@ class MediaCarouselScrollHandler( /** Whether the media card is visible to user if any */ var visibleToUser: Boolean = false + set(value) { + if (field != value) { + field = value + seekBarUpdateListener.invoke(field) + } + } /** Whether the quick setting is expanded or not */ var qsExpanded: Boolean = false diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java index 7f420a8d1055..767706209475 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java @@ -346,6 +346,11 @@ public class MediaControlPanel { mSeekBarViewModel.setListening(listening); } + @VisibleForTesting + public boolean getListening() { + return mSeekBarViewModel.getListening(); + } + /** Sets whether the user is touching the seek bar to change the track position. */ private void setIsScrubbing(boolean isScrubbing) { if (mMediaData == null || mMediaData.getSemanticActions() == null) { diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt index 1e6002cdc717..b9b0459ad615 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt @@ -311,16 +311,15 @@ constructor( } // media player - val controlsTop = - calculateWidgetGroupAlphaForSquishiness( - controlIds, - squishedViewState.measureHeight.toFloat(), - squishedViewState, - squishFraction - ) + calculateWidgetGroupAlphaForSquishiness( + controlIds, + squishedViewState.measureHeight.toFloat(), + squishedViewState, + squishFraction + ) calculateWidgetGroupAlphaForSquishiness( detailIds, - controlsTop, + squishedViewState.measureHeight.toFloat(), squishedViewState, squishFraction ) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java index 85282a1d6c12..e95106e0987a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaDataUtils.java @@ -16,6 +16,7 @@ package com.android.systemui.media.controls.util; +import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -61,8 +62,9 @@ public class MediaDataUtils { * @param extras * @return the progress value between 0-1 inclusive if prsent, otherwise null */ - public static Double getDescriptionProgress(Bundle extras) { - if (!extras.containsKey(MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS)) { + public static Double getDescriptionProgress(@Nullable Bundle extras) { + if (extras == null + || !extras.containsKey(MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS)) { return null; } diff --git a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java index 7db293d96a50..245cf89a8337 100644 --- a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java @@ -16,11 +16,16 @@ package com.android.systemui.process; +import javax.inject.Inject; + /** * A simple wrapper that provides access to process-related details. This facilitates testing by * providing a mockable target around these details. */ public class ProcessWrapper { + @Inject + public ProcessWrapper() {} + public int getUserHandleIdentifier() { return android.os.Process.myUserHandle().getIdentifier(); } diff --git a/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt b/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt new file mode 100644 index 000000000000..62c99da5ed81 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qrcodescanner.dagger + +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tiles.QRCodeScannerTile +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import dagger.multibindings.StringKey + +@Module +interface QRCodeScannerModule { + + /** + */ + @Binds + @IntoMap + @StringKey(QRCodeScannerTile.TILE_SPEC) + fun bindQRCodeScannerTile(qrCodeScannerTile: QRCodeScannerTile): QSTileImpl<*> +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java index 25a5c61a5f7d..27ae1710467b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java @@ -30,6 +30,7 @@ import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QSTileHost; import com.android.systemui.qs.ReduceBrightColorsController; import com.android.systemui.qs.external.QSExternalModule; +import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.ManagedProfileController; import com.android.systemui.statusbar.policy.CastController; @@ -40,11 +41,14 @@ import com.android.systemui.statusbar.policy.SafetyController; import com.android.systemui.statusbar.policy.WalletController; import com.android.systemui.util.settings.SecureSettings; +import java.util.Map; + import javax.inject.Named; import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.Multibinds; /** * Module for QS dependencies @@ -53,6 +57,11 @@ import dagger.Provides; includes = {MediaModule.class, QSExternalModule.class, QSFlagsModule.class}) public interface QSModule { + /** A map of internal QS tiles. Ensures that this can be injected even if + * it is empty */ + @Multibinds + Map<String, QSTileImpl<?>> tileMap(); + @Provides @SysUISingleton static AutoTileManager provideAutoTileManager( diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index 24a4f60b7c00..6b23f5d77145 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -27,74 +27,32 @@ import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTileView; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.external.CustomTile; -import com.android.systemui.qs.tiles.AirplaneModeTile; -import com.android.systemui.qs.tiles.AlarmTile; -import com.android.systemui.qs.tiles.BatterySaverTile; -import com.android.systemui.qs.tiles.BluetoothTile; -import com.android.systemui.qs.tiles.CameraToggleTile; -import com.android.systemui.qs.tiles.CastTile; -import com.android.systemui.qs.tiles.ColorCorrectionTile; -import com.android.systemui.qs.tiles.ColorInversionTile; -import com.android.systemui.qs.tiles.DataSaverTile; -import com.android.systemui.qs.tiles.DeviceControlsTile; -import com.android.systemui.qs.tiles.DndTile; -import com.android.systemui.qs.tiles.DreamTile; -import com.android.systemui.qs.tiles.FlashlightTile; -import com.android.systemui.qs.tiles.HotspotTile; -import com.android.systemui.qs.tiles.InternetTile; -import com.android.systemui.qs.tiles.LocationTile; -import com.android.systemui.qs.tiles.MicrophoneToggleTile; -import com.android.systemui.qs.tiles.NfcTile; -import com.android.systemui.qs.tiles.NightDisplayTile; -import com.android.systemui.qs.tiles.OneHandedModeTile; -import com.android.systemui.qs.tiles.QRCodeScannerTile; -import com.android.systemui.qs.tiles.QuickAccessWalletTile; -import com.android.systemui.qs.tiles.ReduceBrightColorsTile; -import com.android.systemui.qs.tiles.RotationLockTile; -import com.android.systemui.qs.tiles.ScreenRecordTile; -import com.android.systemui.qs.tiles.UiModeNightTile; -import com.android.systemui.qs.tiles.WorkModeTile; import com.android.systemui.util.leak.GarbageMonitor; +import java.util.Map; + import javax.inject.Inject; import javax.inject.Provider; import dagger.Lazy; +/** + * A factory that creates Quick Settings tiles based on a tileSpec + * + * To create a new tile within SystemUI, the tile class should extend {@link QSTileImpl} and have + * a public static final TILE_SPEC field which serves as a unique key for this tile. (e.g. {@link + * com.android.systemui.qs.tiles.DreamTile#TILE_SPEC}) + * + * After, create or find an existing Module class to house the tile's binding method (e.g. {@link + * com.android.systemui.accessibility.AccessibilityModule}). If creating a new module, add your + * module to the SystemUI dagger graph by including it in an appropriate module. + */ @SysUISingleton public class QSFactoryImpl implements QSFactory { private static final String TAG = "QSFactory"; - private final Provider<InternetTile> mInternetTileProvider; - private final Provider<BluetoothTile> mBluetoothTileProvider; - private final Provider<DndTile> mDndTileProvider; - private final Provider<ColorCorrectionTile> mColorCorrectionTileProvider; - private final Provider<ColorInversionTile> mColorInversionTileProvider; - private final Provider<AirplaneModeTile> mAirplaneModeTileProvider; - private final Provider<WorkModeTile> mWorkModeTileProvider; - private final Provider<RotationLockTile> mRotationLockTileProvider; - private final Provider<FlashlightTile> mFlashlightTileProvider; - private final Provider<LocationTile> mLocationTileProvider; - private final Provider<CastTile> mCastTileProvider; - private final Provider<HotspotTile> mHotspotTileProvider; - private final Provider<BatterySaverTile> mBatterySaverTileProvider; - private final Provider<DataSaverTile> mDataSaverTileProvider; - private final Provider<NightDisplayTile> mNightDisplayTileProvider; - private final Provider<NfcTile> mNfcTileProvider; - private final Provider<GarbageMonitor.MemoryTile> mMemoryTileProvider; - private final Provider<UiModeNightTile> mUiModeNightTileProvider; - private final Provider<ScreenRecordTile> mScreenRecordTileProvider; - private final Provider<ReduceBrightColorsTile> mReduceBrightColorsTileProvider; - private final Provider<CameraToggleTile> mCameraToggleTileProvider; - private final Provider<MicrophoneToggleTile> mMicrophoneToggleTileProvider; - private final Provider<DeviceControlsTile> mDeviceControlsTileProvider; - private final Provider<AlarmTile> mAlarmTileProvider; - private final Provider<QuickAccessWalletTile> mQuickAccessWalletTileProvider; - private final Provider<QRCodeScannerTile> mQRCodeScannerTileProvider; - private final Provider<OneHandedModeTile> mOneHandedModeTileProvider; - private final Provider<DreamTile> mDreamTileProvider; - + protected final Map<String, Provider<QSTileImpl<?>>> mTileMap; private final Lazy<QSHost> mQsHostLazy; private final Provider<CustomTile.Builder> mCustomTileBuilderProvider; @@ -102,65 +60,10 @@ public class QSFactoryImpl implements QSFactory { public QSFactoryImpl( Lazy<QSHost> qsHostLazy, Provider<CustomTile.Builder> customTileBuilderProvider, - Provider<InternetTile> internetTileProvider, - Provider<BluetoothTile> bluetoothTileProvider, - Provider<DndTile> dndTileProvider, - Provider<ColorInversionTile> colorInversionTileProvider, - Provider<AirplaneModeTile> airplaneModeTileProvider, - Provider<WorkModeTile> workModeTileProvider, - Provider<RotationLockTile> rotationLockTileProvider, - Provider<FlashlightTile> flashlightTileProvider, - Provider<LocationTile> locationTileProvider, - Provider<CastTile> castTileProvider, - Provider<HotspotTile> hotspotTileProvider, - Provider<BatterySaverTile> batterySaverTileProvider, - Provider<DataSaverTile> dataSaverTileProvider, - Provider<NightDisplayTile> nightDisplayTileProvider, - Provider<NfcTile> nfcTileProvider, - Provider<GarbageMonitor.MemoryTile> memoryTileProvider, - Provider<UiModeNightTile> uiModeNightTileProvider, - Provider<ScreenRecordTile> screenRecordTileProvider, - Provider<ReduceBrightColorsTile> reduceBrightColorsTileProvider, - Provider<CameraToggleTile> cameraToggleTileProvider, - Provider<MicrophoneToggleTile> microphoneToggleTileProvider, - Provider<DeviceControlsTile> deviceControlsTileProvider, - Provider<AlarmTile> alarmTileProvider, - Provider<QuickAccessWalletTile> quickAccessWalletTileProvider, - Provider<QRCodeScannerTile> qrCodeScannerTileProvider, - Provider<OneHandedModeTile> oneHandedModeTileProvider, - Provider<ColorCorrectionTile> colorCorrectionTileProvider, - Provider<DreamTile> dreamTileProvider) { + Map<String, Provider<QSTileImpl<?>>> tileMap) { mQsHostLazy = qsHostLazy; mCustomTileBuilderProvider = customTileBuilderProvider; - - mInternetTileProvider = internetTileProvider; - mBluetoothTileProvider = bluetoothTileProvider; - mDndTileProvider = dndTileProvider; - mColorInversionTileProvider = colorInversionTileProvider; - mAirplaneModeTileProvider = airplaneModeTileProvider; - mWorkModeTileProvider = workModeTileProvider; - mRotationLockTileProvider = rotationLockTileProvider; - mFlashlightTileProvider = flashlightTileProvider; - mLocationTileProvider = locationTileProvider; - mCastTileProvider = castTileProvider; - mHotspotTileProvider = hotspotTileProvider; - mBatterySaverTileProvider = batterySaverTileProvider; - mDataSaverTileProvider = dataSaverTileProvider; - mNightDisplayTileProvider = nightDisplayTileProvider; - mNfcTileProvider = nfcTileProvider; - mMemoryTileProvider = memoryTileProvider; - mUiModeNightTileProvider = uiModeNightTileProvider; - mScreenRecordTileProvider = screenRecordTileProvider; - mReduceBrightColorsTileProvider = reduceBrightColorsTileProvider; - mCameraToggleTileProvider = cameraToggleTileProvider; - mMicrophoneToggleTileProvider = microphoneToggleTileProvider; - mDeviceControlsTileProvider = deviceControlsTileProvider; - mAlarmTileProvider = alarmTileProvider; - mQuickAccessWalletTileProvider = quickAccessWalletTileProvider; - mQRCodeScannerTileProvider = qrCodeScannerTileProvider; - mOneHandedModeTileProvider = oneHandedModeTileProvider; - mColorCorrectionTileProvider = colorCorrectionTileProvider; - mDreamTileProvider = dreamTileProvider; + mTileMap = tileMap; } /** Creates a tile with a type based on {@code tileSpec} */ @@ -177,61 +80,10 @@ public class QSFactoryImpl implements QSFactory { @Nullable protected QSTileImpl createTileInternal(String tileSpec) { // Stock tiles. - switch (tileSpec) { - case "internet": - return mInternetTileProvider.get(); - case "bt": - return mBluetoothTileProvider.get(); - case "dnd": - return mDndTileProvider.get(); - case "inversion": - return mColorInversionTileProvider.get(); - case "airplane": - return mAirplaneModeTileProvider.get(); - case "work": - return mWorkModeTileProvider.get(); - case "rotation": - return mRotationLockTileProvider.get(); - case "flashlight": - return mFlashlightTileProvider.get(); - case "location": - return mLocationTileProvider.get(); - case "cast": - return mCastTileProvider.get(); - case "hotspot": - return mHotspotTileProvider.get(); - case "battery": - return mBatterySaverTileProvider.get(); - case "saver": - return mDataSaverTileProvider.get(); - case "night": - return mNightDisplayTileProvider.get(); - case "nfc": - return mNfcTileProvider.get(); - case "dark": - return mUiModeNightTileProvider.get(); - case "screenrecord": - return mScreenRecordTileProvider.get(); - case "reduce_brightness": - return mReduceBrightColorsTileProvider.get(); - case "cameratoggle": - return mCameraToggleTileProvider.get(); - case "mictoggle": - return mMicrophoneToggleTileProvider.get(); - case "controls": - return mDeviceControlsTileProvider.get(); - case "alarm": - return mAlarmTileProvider.get(); - case "wallet": - return mQuickAccessWalletTileProvider.get(); - case "qr_code_scanner": - return mQRCodeScannerTileProvider.get(); - case "onehanded": - return mOneHandedModeTileProvider.get(); - case "color_correction": - return mColorCorrectionTileProvider.get(); - case "dream": - return mDreamTileProvider.get(); + if (mTileMap.containsKey(tileSpec) + // We should not return a Garbage Monitory Tile if the build is not Debuggable + && (!tileSpec.equals(GarbageMonitor.MemoryTile.TILE_SPEC) || Build.IS_DEBUGGABLE)) { + return mTileMap.get(tileSpec).get(); } // Custom tiles @@ -240,13 +92,6 @@ public class QSFactoryImpl implements QSFactory { mCustomTileBuilderProvider.get(), tileSpec, mQsHostLazy.get().getUserContext()); } - // Debug tiles. - if (Build.IS_DEBUGGABLE) { - if (tileSpec.equals(GarbageMonitor.MemoryTile.TILE_SPEC)) { - return mMemoryTileProvider.get(); - } - } - // Broken tiles. Log.w(TAG, "No stock tile spec: " + tileSpec); return null; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt index 29d7fb02e613..d0b04c93bba0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt @@ -694,7 +694,8 @@ internal object SubtitleArrayMapping { "alarm" to R.array.tile_states_alarm, "onehanded" to R.array.tile_states_onehanded, "color_correction" to R.array.tile_states_color_correction, - "dream" to R.array.tile_states_dream + "dream" to R.array.tile_states_dream, + "font_scaling" to R.array.tile_states_font_scaling ) fun getSubtitleId(spec: String?): Int { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java index 033dbe0f82ee..92a83bba8a68 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java @@ -57,6 +57,9 @@ import dagger.Lazy; /** Quick settings tile: Airplane mode **/ public class AirplaneModeTile extends QSTileImpl<BooleanState> { + + public static final String TILE_SPEC = "airplane"; + private final SettingObserver mSetting; private final BroadcastDispatcher mBroadcastDispatcher; private final Lazy<ConnectivityManager> mLazyConnectivityManager; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt index 14e0f707d3b5..2ca452e45ecf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt @@ -118,4 +118,8 @@ class AlarmTile @Inject constructor( override fun getLongClickIntent(): Intent? { return null } -}
\ No newline at end of file + + companion object { + const val TILE_SPEC = "alarm" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java index ee49b294dfcd..027a464251c9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java @@ -48,6 +48,8 @@ import javax.inject.Inject; public class BatterySaverTile extends QSTileImpl<BooleanState> implements BatteryController.BatteryStateChangeCallback { + public static final String TILE_SPEC = "battery"; + private final BatteryController mBatteryController; @VisibleForTesting protected final SettingObserver mSetting; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 9a0d0d9656ca..df1c8dfdde96 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -55,6 +55,9 @@ import javax.inject.Inject; /** Quick settings tile: Bluetooth **/ public class BluetoothTile extends QSTileImpl<BooleanState> { + + public static final String TILE_SPEC = "bt"; + private static final Intent BLUETOOTH_SETTINGS = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS); private final BluetoothController mController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java index ee41f1d1077d..93e5f1efbdc8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java @@ -45,6 +45,8 @@ import javax.inject.Inject; public class CameraToggleTile extends SensorPrivacyToggleTile { + public static final String TILE_SPEC = "cameratoggle"; + @Inject protected CameraToggleTile(QSHost host, @Background Looper backgroundLooper, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index dce137f5b9f3..8d984817ba77 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -66,7 +66,9 @@ import javax.inject.Inject; /** Quick settings tile: Cast **/ public class CastTile extends QSTileImpl<BooleanState> { - private static final String INTERACTION_JANK_TAG = "cast"; + public static final String TILE_SPEC = "cast"; + + private static final String INTERACTION_JANK_TAG = TILE_SPEC; private static final Intent CAST_SETTINGS = new Intent(Settings.ACTION_CAST_SETTINGS); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java index 6dfcf5ccc258..b6205d5df63d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java @@ -48,6 +48,8 @@ import javax.inject.Inject; /** Quick settings tile: Color correction **/ public class ColorCorrectionTile extends QSTileImpl<BooleanState> { + public static final String TILE_SPEC = "color_correction"; + private final Icon mIcon = ResourceIcon.get(drawable.ic_qs_color_correction); private final SettingObserver mSetting; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java index a31500c6bb18..9a44e83ad9a1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -49,6 +49,7 @@ import javax.inject.Inject; /** Quick settings tile: Invert colors **/ public class ColorInversionTile extends QSTileImpl<BooleanState> { + public static final String TILE_SPEC = "inversion"; private final SettingObserver mSetting; @Inject diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java index 2fc99f323611..add517e18516 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java @@ -48,6 +48,8 @@ import javax.inject.Inject; public class DataSaverTile extends QSTileImpl<BooleanState> implements DataSaverController.Listener{ + public static final String TILE_SPEC = "saver"; + private static final String INTERACTION_JANK_TAG = "start_data_saver"; private final DataSaverController mDataSaverController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt index 41d854969e20..01164fb0a009 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt @@ -159,4 +159,8 @@ class DeviceControlsTile @Inject constructor( override fun getTileLabel(): CharSequence { return mContext.getText(controlsComponent.getTileTitleId()) } + + companion object { + const val TILE_SPEC = "controls" + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index 8b7f53fa5a3f..434fe45f47c0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -67,6 +67,8 @@ import javax.inject.Inject; /** Quick settings tile: Do not disturb **/ public class DndTile extends QSTileImpl<BooleanState> { + public static final String TILE_SPEC = "dnd"; + private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java index 5bc209a840cb..53774e82602b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java @@ -60,6 +60,8 @@ import javax.inject.Named; /** Quick settings tile: Screensaver (dream) **/ public class DreamTile extends QSTileImpl<QSTile.BooleanState> { + public static final String TILE_SPEC = "dream"; + private static final String LOG_TAG = "QSDream"; // TODO: consider 1 animated icon instead private final Icon mIconDocked = ResourceIcon.get(R.drawable.ic_qs_screen_saver); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index a74792687289..e091a750fbec 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -49,6 +49,7 @@ import javax.inject.Inject; public class FlashlightTile extends QSTileImpl<BooleanState> implements FlashlightController.FlashlightListener { + public static final String TILE_SPEC = "flashlight"; private final FlashlightController mFlashlightController; @Inject diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt new file mode 100644 index 000000000000..721046d217c9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.qs.tiles + +import android.content.Intent +import android.os.Handler +import android.os.Looper +import android.view.View +import com.android.internal.jank.InteractionJankMonitor +import com.android.internal.logging.MetricsLogger +import com.android.systemui.R +import com.android.systemui.accessibility.fontscaling.FontScalingDialog +import com.android.systemui.animation.DialogCuj +import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.qs.QSHost +import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.util.settings.SystemSettings +import javax.inject.Inject + +class FontScalingTile +@Inject +constructor( + host: QSHost, + @Background backgroundLooper: Looper, + @Main mainHandler: Handler, + falsingManager: FalsingManager, + metricsLogger: MetricsLogger, + statusBarStateController: StatusBarStateController, + activityStarter: ActivityStarter, + qsLogger: QSLogger, + private val dialogLaunchAnimator: DialogLaunchAnimator, + private val systemSettings: SystemSettings +) : + QSTileImpl<QSTile.State?>( + host, + backgroundLooper, + mainHandler, + falsingManager, + metricsLogger, + statusBarStateController, + activityStarter, + qsLogger + ) { + private val icon = ResourceIcon.get(R.drawable.ic_qs_font_scaling) + + override fun isAvailable(): Boolean { + return false + } + + override fun newTileState(): QSTile.State { + val state = QSTile.State() + state.handlesLongClick = false + return state + } + + override fun handleClick(view: View?) { + mUiHandler.post { + val dialog: SystemUIDialog = FontScalingDialog(mContext, systemSettings) + if (view != null) { + dialogLaunchAnimator.showFromView( + dialog, + view, + DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG) + ) + } else { + dialog.show() + } + } + } + + override fun handleUpdateState(state: QSTile.State?, arg: Any?) { + state?.label = mContext.getString(R.string.quick_settings_font_scaling_label) + state?.icon = icon + } + + override fun getLongClickIntent(): Intent? { + return null + } + + override fun getTileLabel(): CharSequence { + return mContext.getString(R.string.quick_settings_font_scaling_label) + } + + companion object { + const val TILE_SPEC = "font_scaling" + private const val INTERACTION_JANK_TAG = "font_scaling" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index 624def60276b..6bf8b7666054 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -51,6 +51,7 @@ import javax.inject.Inject; /** Quick settings tile: Hotspot **/ public class HotspotTile extends QSTileImpl<BooleanState> { + public static final String TILE_SPEC = "hotspot"; private final HotspotController mHotspotController; private final DataSaverController mDataSaverController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java index 1c60486a6909..12e9aebc58f7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java @@ -67,6 +67,9 @@ import javax.inject.Inject; /** Quick settings tile: Internet **/ public class InternetTile extends QSTileImpl<SignalState> { + + public static final String TILE_SPEC = "internet"; + private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS); protected final NetworkController mController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java index 9466a694ea1b..89d402a3af5a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java @@ -48,6 +48,8 @@ import javax.inject.Inject; /** Quick settings tile: Location **/ public class LocationTile extends QSTileImpl<BooleanState> { + public static final String TILE_SPEC = "location"; + private final LocationController mController; private final KeyguardStateController mKeyguard; private final Callback mCallback = new Callback(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java index e54709562c10..2e475d40d55f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java @@ -45,6 +45,8 @@ import javax.inject.Inject; public class MicrophoneToggleTile extends SensorPrivacyToggleTile { + public static final String TILE_SPEC = "mictoggle"; + @Inject protected MicrophoneToggleTile(QSHost host, @Background Looper backgroundLooper, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java index a61f0ce0c864..e189f80a7c23 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java @@ -51,7 +51,9 @@ import javax.inject.Inject; /** Quick settings tile: Enable/Disable NFC **/ public class NfcTile extends QSTileImpl<BooleanState> { - private static final String NFC = "nfc"; + public static final String TILE_SPEC = "nfc"; + + private static final String NFC = TILE_SPEC; private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_nfc); @Nullable diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java index 0e9f6599522f..aacd53bde51c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java @@ -61,6 +61,8 @@ import javax.inject.Inject; public class NightDisplayTile extends QSTileImpl<BooleanState> implements NightDisplayListener.Callback { + public static final String TILE_SPEC = "night"; + /** * Pattern for {@link java.time.format.DateTimeFormatter} used to approximate the time to the * nearest hour and add on the AM/PM indicator. diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java index 7e1712455e72..ae67d99ea2fb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java @@ -47,6 +47,9 @@ import javax.inject.Inject; /** Quick settings tile: One-handed mode **/ public class OneHandedModeTile extends QSTileImpl<BooleanState> { + + public static final String TILE_SPEC = "onehanded"; + private final Icon mIcon = ResourceIcon.get( com.android.internal.R.drawable.ic_qs_one_handed_mode); private final SettingObserver mSetting; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java index 6d50b562cd02..92f52724ca0c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java @@ -44,6 +44,9 @@ import javax.inject.Inject; /** Quick settings tile: QR Code Scanner **/ public class QRCodeScannerTile extends QSTileImpl<QSTile.State> { + + public static final String TILE_SPEC = "qr_code_scanner"; + private static final String TAG = "QRCodeScanner"; private final CharSequence mLabel = mContext.getString(R.string.qr_code_scanner_title); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java index 248c78e557cc..4a3c56328006 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java @@ -62,6 +62,8 @@ import javax.inject.Inject; /** Quick settings tile: Quick access wallet **/ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> { + public static final String TILE_SPEC = "wallet"; + private static final String TAG = "QuickAccessWalletTile"; private static final String FEATURE_CHROME_OS = "org.chromium.arc"; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java index 1dac33909ba7..10f1ce4946c8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java @@ -49,6 +49,7 @@ import javax.inject.Named; public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> implements ReduceBrightColorsController.Listener{ + public static final String TILE_SPEC = "reduce_brightness"; private final boolean mIsAvailable; private final ReduceBrightColorsController mReduceBrightColorsController; private boolean mIsListening; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java index 600874f0d01a..8888c733c3c1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java @@ -57,6 +57,9 @@ import javax.inject.Inject; /** Quick settings tile: Rotation **/ public class RotationLockTile extends QSTileImpl<BooleanState> implements BatteryController.BatteryStateChangeCallback { + + public static final String TILE_SPEC = "rotation"; + private static final String EMPTY_SECONDARY_STRING = ""; private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_auto_rotate); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java index ad000690a354..07b50c9a66f6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java @@ -54,6 +54,9 @@ import javax.inject.Inject; */ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> implements RecordingController.RecordingStateChangeCallback { + + public static final String TILE_SPEC = "screenrecord"; + private static final String TAG = "ScreenRecordTile"; private static final String INTERACTION_JANK_TAG = "screen_record"; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java index 92f6690a13e7..809689cb806d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java @@ -17,7 +17,6 @@ package com.android.systemui.qs.tiles; import android.app.UiModeManager; -import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.os.Handler; @@ -60,6 +59,9 @@ import javax.inject.Inject; public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements ConfigurationController.ConfigurationListener, BatteryController.BatteryStateChangeCallback { + + public static final String TILE_SPEC = "dark"; + public static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm a"); private final UiModeManager mUiModeManager; private final BatteryController mBatteryController; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java index 72c6bfe371ce..6a5c99032457 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java @@ -49,6 +49,9 @@ import javax.inject.Inject; /** Quick settings tile: Work profile on/off */ public class WorkModeTile extends QSTileImpl<BooleanState> implements ManagedProfileController.Callback { + + public static final String TILE_SPEC = "work"; + private final Icon mIcon = ResourceIcon.get(R.drawable.stat_sys_managed_profile_status); private final ManagedProfileController mProfileController; diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java index 802db7e9d0c0..dc3c8203d1a2 100644 --- a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java @@ -27,7 +27,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.CoreStartable; 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.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.SystemUIDialog; diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index a979e5a99fa8..25ff308b46bb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -25,6 +25,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING; @@ -99,6 +100,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarWindowCallback; import com.android.systemui.statusbar.policy.CallbackController; +import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder; import com.android.wm.shell.sysui.ShellInterface; import java.io.PrintWriter; @@ -144,6 +146,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private final CommandQueue mCommandQueue; private final UserTracker mUserTracker; private final KeyguardUnlockAnimationController mSysuiUnlockAnimationController; + private final Optional<UnfoldTransitionProgressForwarder> mUnfoldTransitionProgressForwarder; private final UiEventLogger mUiEventLogger; private final DisplayTracker mDisplayTracker; @@ -415,6 +418,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows); params.putBinder(KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER, mSysuiUnlockAnimationController.asBinder()); + mUnfoldTransitionProgressForwarder.ifPresent( + unfoldProgressForwarder -> params.putBinder( + KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER, + unfoldProgressForwarder.asBinder())); // Add all the interfaces exposed by the shell mShellInterface.createExternalInterfaces(params); @@ -512,7 +519,9 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis DisplayTracker displayTracker, KeyguardUnlockAnimationController sysuiUnlockAnimationController, AssistUtils assistUtils, - DumpManager dumpManager) { + DumpManager dumpManager, + Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder + ) { // b/241601880: This component shouldn't be running for a non-primary user if (!Process.myUserHandle().equals(UserHandle.SYSTEM)) { Log.e(TAG_OPS, "Unexpected initialization for non-primary user", new Throwable()); @@ -538,6 +547,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis mSysUiState.addCallback(this::notifySystemUiStateFlags); mUiEventLogger = uiEventLogger; mDisplayTracker = displayTracker; + mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder; dumpManager.registerDumpable(getClass().getSimpleName(), this); diff --git a/packages/SystemUI/src/com/android/systemui/rotationlock/RotationLockModule.kt b/packages/SystemUI/src/com/android/systemui/rotationlock/RotationLockModule.kt new file mode 100644 index 000000000000..9abe90fb05d4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/rotationlock/RotationLockModule.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.rotationlock + +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tiles.RotationLockTile +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import dagger.multibindings.StringKey + +@Module +interface RotationLockModule { + + /** Inject RotationLockTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(RotationLockTile.TILE_SPEC) + fun bindRotationLockTile(rotationLockTile: RotationLockTile): QSTileImpl<*> +} diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordModule.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordModule.kt new file mode 100644 index 000000000000..7467805d73ec --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordModule.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.screenrecord + +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tiles.ScreenRecordTile +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import dagger.multibindings.StringKey + +@Module +interface ScreenRecordModule { + /** Inject ScreenRecordTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(ScreenRecordTile.TILE_SPEC) + fun bindScreenRecordTile(screenRecordTile: ScreenRecordTile): QSTileImpl<*> +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 72a8e23fbff5..8721d71897f7 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -99,6 +99,7 @@ import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.clipboardoverlay.ClipboardOverlayController; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition; import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback; import com.android.systemui.settings.DisplayTracker; @@ -480,7 +481,7 @@ public class ScreenshotController { } mScreenshotView.setScreenshot(screenshot); - if (screenshot.getTaskId() >= 0) { + if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && screenshot.getTaskId() >= 0) { mAssistContentRequester.requestAssistContent(screenshot.getTaskId(), new AssistContentRequester.Callback() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java index 8035d19e3b8f..111278a002f9 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java @@ -225,7 +225,7 @@ public class TakeScreenshotService extends Service { return; } - if (mFeatureFlags.isEnabled(Flags.SCREENSHOT_METADATA)) { + if (mFeatureFlags.isEnabled(Flags.SCREENSHOT_METADATA_REFACTOR)) { Log.d(TAG, "Processing screenshot data"); ScreenshotData screenshotData = ScreenshotData.fromRequest(request); try { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 56c34a0b3665..8f1e0a1a6b16 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -23,6 +23,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.IndentingPrintWriter; import android.util.MathUtils; import android.view.View; import android.view.ViewGroup; @@ -52,6 +53,9 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm; import com.android.systemui.statusbar.notification.stack.ViewState; import com.android.systemui.statusbar.phone.NotificationIconContainer; +import com.android.systemui.util.DumpUtilsKt; + +import java.io.PrintWriter; /** * A notification shelf view that is placed inside the notification scroller. It manages the @@ -86,7 +90,6 @@ public class NotificationShelf extends ActivatableNotificationView implements private boolean mInteractive; private boolean mAnimationsEnabled = true; private boolean mShowNotificationShelf; - private float mFirstElementRoundness; private Rect mClipRect = new Rect(); private int mIndexOfFirstViewInShelf = -1; private float mCornerAnimationDistance; @@ -263,8 +266,7 @@ public class NotificationShelf extends ActivatableNotificationView implements final float actualWidth = mAmbientState.isOnKeyguard() ? MathUtils.lerp(shortestWidth, getWidth(), fractionToShade) : getWidth(); - ActivatableNotificationView anv = (ActivatableNotificationView) this; - anv.setBackgroundWidth((int) actualWidth); + setBackgroundWidth((int) actualWidth); if (mShelfIcons != null) { mShelfIcons.setActualLayoutWidth((int) actualWidth); } @@ -365,9 +367,7 @@ public class NotificationShelf extends ActivatableNotificationView implements boolean expandingAnimated = mAmbientState.isExpansionChanging() && !mAmbientState.isPanelTracking(); int baseZHeight = mAmbientState.getBaseZHeight(); - int backgroundTop = 0; int clipTopAmount = 0; - float firstElementRoundness = 0.0f; for (int i = 0; i < mHostLayoutController.getChildCount(); i++) { ExpandableView child = mHostLayoutController.getChildAt(i); @@ -420,18 +420,6 @@ public class NotificationShelf extends ActivatableNotificationView implements if (notGoneIndex != 0 || !aboveShelf) { expandableRow.setAboveShelf(false); } - if (notGoneIndex == 0) { - StatusBarIconView icon = expandableRow.getEntry().getIcons().getShelfIcon(); - NotificationIconContainer.IconState iconState = getIconState(icon); - // The icon state might be null in rare cases where the notification is actually - // added to the layout, but not to the shelf. An example are replied messages, - // since they don't show up on AOD - if (iconState != null && iconState.clampedAppearAmount == 1.0f) { - // only if the first icon is fully in the shelf we want to clip to it! - backgroundTop = (int) (child.getTranslationY() - getTranslationY()); - firstElementRoundness = expandableRow.getTopRoundness(); - } - } previousColor = ownColorUntinted; notGoneIndex++; @@ -467,8 +455,6 @@ public class NotificationShelf extends ActivatableNotificationView implements // TODO(b/172289889) transition last icon in shelf to notification icon and vice versa. setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE); - setBackgroundTop(backgroundTop); - setFirstElementRoundness(firstElementRoundness); mShelfIcons.setSpeedBumpIndex(mHostLayoutController.getSpeedBumpIndex()); mShelfIcons.calculateIconXTranslations(); mShelfIcons.applyIconStates(); @@ -570,12 +556,6 @@ public class NotificationShelf extends ActivatableNotificationView implements } } - private void setFirstElementRoundness(float firstElementRoundness) { - if (mFirstElementRoundness != firstElementRoundness) { - mFirstElementRoundness = firstElementRoundness; - } - } - private void updateIconClipAmount(ExpandableNotificationRow row) { float maxTop = row.getTranslationY(); if (getClipTopAmount() != 0) { @@ -1011,6 +991,18 @@ public class NotificationShelf extends ActivatableNotificationView implements expandableView.requestRoundnessReset(LegacySourceType.OnScroll); } + @Override + public void dump(PrintWriter pwOriginal, String[] args) { + IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal); + super.dump(pw, args); + if (DUMP_VERBOSE) { + DumpUtilsKt.withIncreasedIndent(pw, () -> { + pw.println("mActualWidth: " + mActualWidth); + pw.println("mStatusBarHeight: " + mStatusBarHeight); + }); + } + } + public class ShelfState extends ExpandableViewState { private boolean hasItemsInStableShelf; private ExpandableView firstViewInShelf; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt new file mode 100644 index 000000000000..1099810f972f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.connectivity + +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tiles.AirplaneModeTile +import com.android.systemui.qs.tiles.BluetoothTile +import com.android.systemui.qs.tiles.CastTile +import com.android.systemui.qs.tiles.DataSaverTile +import com.android.systemui.qs.tiles.HotspotTile +import com.android.systemui.qs.tiles.InternetTile +import com.android.systemui.qs.tiles.NfcTile +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import dagger.multibindings.StringKey + +@Module +interface ConnectivityModule { + + /** Inject InternetTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(InternetTile.TILE_SPEC) + fun bindInternetTile(internetTile: InternetTile): QSTileImpl<*> + + /** Inject BluetoothTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(BluetoothTile.TILE_SPEC) + fun bindBluetoothTile(bluetoothTile: BluetoothTile): QSTileImpl<*> + + /** Inject CastTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(CastTile.TILE_SPEC) + fun bindCastTile(castTile: CastTile): QSTileImpl<*> + + /** Inject HotspotTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(HotspotTile.TILE_SPEC) + fun bindHotspotTile(hotspotTile: HotspotTile): QSTileImpl<*> + + /** Inject AirplaneModeTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(AirplaneModeTile.TILE_SPEC) + fun bindAirplaneModeTile(airplaneModeTile: AirplaneModeTile): QSTileImpl<*> + + /** Inject DataSaverTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(DataSaverTile.TILE_SPEC) + fun bindDataSaverTile(dataSaverTile: DataSaverTile): QSTileImpl<*> + + /** Inject NfcTile into tileMap in QSModule */ + @Binds @IntoMap @StringKey(NfcTile.TILE_SPEC) fun bindNfcTile(nfcTile: NfcTile): QSTileImpl<*> +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt index 48567592c43e..fc89be2c6670 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt @@ -17,13 +17,16 @@ package com.android.systemui.statusbar.notification import android.content.Context +import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.FlagResolver +import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import javax.inject.Inject class NotifPipelineFlags @Inject constructor( val context: Context, - val featureFlags: FeatureFlags + val featureFlags: FeatureFlags, + val sysPropFlags: FlagResolver, ) { init { featureFlags.addListener(Flags.DISABLE_FSI) { event -> event.requestNoRestart() } @@ -39,11 +42,21 @@ class NotifPipelineFlags @Inject constructor( fun disableFsi(): Boolean = featureFlags.isEnabled(Flags.DISABLE_FSI) - val shouldFilterUnseenNotifsOnKeyguard: Boolean by lazy { - featureFlags.isEnabled(Flags.FILTER_UNSEEN_NOTIFS_ON_KEYGUARD) - } + fun forceDemoteFsi(): Boolean = + sysPropFlags.isEnabled(NotificationFlags.FSI_FORCE_DEMOTE) - val isNoHunForOldWhenEnabled: Boolean by lazy { - featureFlags.isEnabled(Flags.NO_HUN_FOR_OLD_WHEN) - } + fun showStickyHunForDeniedFsi(): Boolean = + sysPropFlags.isEnabled(NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI) + + fun allowDismissOngoing(): Boolean = + sysPropFlags.isEnabled(NotificationFlags.ALLOW_DISMISS_ONGOING) + + fun isOtpRedactionEnabled(): Boolean = + sysPropFlags.isEnabled(NotificationFlags.OTP_REDACTION) + + val shouldFilterUnseenNotifsOnKeyguard: Boolean + get() = featureFlags.isEnabled(Flags.FILTER_UNSEEN_NOTIFS_ON_KEYGUARD) + + val isNoHunForOldWhenEnabled: Boolean + get() = featureFlags.isEnabled(Flags.NO_HUN_FOR_OLD_WHEN) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt index 13b3aca2a88f..27fe747e6be8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt @@ -70,7 +70,15 @@ class NotificationInterruptLogger @Inject constructor( buffer.log(TAG, DEBUG, { str1 = entry.logKey }, { - "No alerting: snoozed package: $str1" + "No heads up: snoozed package: $str1" + }) + } + + fun logHeadsUpPackageSnoozeBypassedHasFsi(entry: NotificationEntry) { + buffer.log(TAG, DEBUG, { + str1 = entry.logKey + }, { + "Heads up: package snooze bypassed because notification has full-screen intent: $str1" }) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java index 9bcf92d63b8f..afeb72fa9eeb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.interruption; import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD; import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR; +import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI; import android.app.Notification; import android.app.NotificationManager; @@ -87,7 +88,10 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD(1236), @UiEvent(doc = "HUN suppressed for old when") - HUN_SUPPRESSED_OLD_WHEN(1237); + HUN_SUPPRESSED_OLD_WHEN(1237), + + @UiEvent(doc = "HUN snooze bypassed for potentially suppressed FSI") + HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI(1269); private final int mId; @@ -409,7 +413,15 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter return false; } - if (isSnoozedPackage(sbn)) { + final boolean isSnoozedPackage = isSnoozedPackage(sbn); + final boolean fsiRequiresKeyguard = mFlags.fullScreenIntentRequiresKeyguard(); + final boolean hasFsi = sbn.getNotification().fullScreenIntent != null; + + // Assume any notification with an FSI is time-sensitive (like an alarm or incoming call) + // and ignore whether HUNs have been snoozed for the package. + final boolean shouldBypassSnooze = fsiRequiresKeyguard && hasFsi; + + if (isSnoozedPackage && !shouldBypassSnooze) { if (log) mLogger.logNoHeadsUpPackageSnoozed(entry); return false; } @@ -447,6 +459,19 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter return false; } } + + if (isSnoozedPackage) { + if (log) { + mLogger.logHeadsUpPackageSnoozeBypassedHasFsi(entry); + final int uid = entry.getSbn().getUid(); + final String packageName = entry.getSbn().getPackageName(); + mUiEventLogger.log(HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI, uid, + packageName); + } + + return true; + } + if (log) mLogger.logHeadsUp(entry); return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 7addc8fe7a15..68ad49befc54 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -23,6 +23,7 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Point; import android.util.AttributeSet; +import android.util.IndentingPrintWriter; import android.util.MathUtils; import android.view.Choreographer; import android.view.MotionEvent; @@ -43,7 +44,9 @@ import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.SourceType; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import com.android.systemui.util.DumpUtilsKt; +import java.io.PrintWriter; import java.util.HashSet; import java.util.Set; @@ -651,11 +654,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundNormal.setRadius(topRadius, bottomRadius); } - @Override - protected void setBackgroundTop(int backgroundTop) { - mBackgroundNormal.setBackgroundTop(backgroundTop); - } - protected abstract View getContentView(); public int calculateBgColor() { @@ -819,6 +817,22 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mOnDetachResetRoundness.add(sourceType); } + @Override + public void dump(PrintWriter pwOriginal, String[] args) { + IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal); + super.dump(pw, args); + if (DUMP_VERBOSE) { + DumpUtilsKt.withIncreasedIndent(pw, () -> { + pw.println("mBackgroundNormal: " + mBackgroundNormal); + if (mBackgroundNormal != null) { + DumpUtilsKt.withIncreasedIndent(pw, () -> { + mBackgroundNormal.dump(pw, args); + }); + } + }); + } + } + public interface OnActivatedListener { void onActivated(ActivatableNotificationView view); void onActivationReset(ActivatableNotificationView view); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java index 20412452b7f9..197caa2d5645 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java @@ -24,12 +24,16 @@ import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; +import android.util.IndentingPrintWriter; import android.view.View; import android.view.ViewOutlineProvider; import com.android.systemui.R; import com.android.systemui.statusbar.notification.RoundableState; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer; +import com.android.systemui.util.DumpUtilsKt; + +import java.io.PrintWriter; /** * Like {@link ExpandableView}, but setting an outline for the height and clipping. @@ -43,7 +47,6 @@ public abstract class ExpandableOutlineView extends ExpandableView { private float mOutlineAlpha = -1f; private boolean mAlwaysRoundBothCorners; private Path mTmpPath = new Path(); - private int mBackgroundTop; /** * {@code false} if the children views of the {@link ExpandableOutlineView} are translated when @@ -59,7 +62,7 @@ public abstract class ExpandableOutlineView extends ExpandableView { // Only when translating just the contents, does the outline need to be shifted. int translation = !mDismissUsingRowTranslationX ? (int) getTranslation() : 0; int left = Math.max(translation, 0); - int top = mClipTopAmount + mBackgroundTop; + int top = mClipTopAmount; int right = getWidth() + Math.min(translation, 0); int bottom = Math.max(getActualHeight() - mClipBottomAmount, top); outline.setRect(left, top, right, bottom); @@ -92,7 +95,7 @@ public abstract class ExpandableOutlineView extends ExpandableView { ? (int) getTranslation() : 0; int halfExtraWidth = (int) (mExtraWidthForClipping / 2.0f); left = Math.max(translation, 0) - halfExtraWidth; - top = mClipTopAmount + mBackgroundTop; + top = mClipTopAmount; right = getWidth() + halfExtraWidth + Math.min(translation, 0); // If the top is rounded we want the bottom to be at most at the top roundness, in order // to avoid the shadow changing when scrolling up. @@ -228,13 +231,6 @@ public abstract class ExpandableOutlineView extends ExpandableView { super.applyRoundnessAndInvalidate(); } - protected void setBackgroundTop(int backgroundTop) { - if (mBackgroundTop != backgroundTop) { - mBackgroundTop = backgroundTop; - invalidateOutline(); - } - } - public void onDensityOrFontScaleChanged() { initDimens(); applyRoundnessAndInvalidate(); @@ -350,4 +346,18 @@ public abstract class ExpandableOutlineView extends ExpandableView { public Path getCustomClipPath(View child) { return null; } + + @Override + public void dump(PrintWriter pwOriginal, String[] args) { + IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal); + super.dump(pw, args); + DumpUtilsKt.withIncreasedIndent(pw, () -> { + pw.println("Roundness: " + getRoundableState().debugString()); + if (DUMP_VERBOSE) { + pw.println("mCustomOutline: " + mCustomOutline + " mOutlineRect: " + mOutlineRect); + pw.println("mOutlineAlpha: " + mOutlineAlpha); + pw.println("mAlwaysRoundBothCorners: " + mAlwaysRoundBothCorners); + } + }); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index 955d7c18f870..25c7264af047 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -51,6 +51,8 @@ import java.util.List; */ public abstract class ExpandableView extends FrameLayout implements Dumpable, Roundable { private static final String TAG = "ExpandableView"; + /** whether the dump() for this class should include verbose details */ + protected static final boolean DUMP_VERBOSE = false; private RoundableState mRoundableState = null; protected OnHeightChangedListener mOnHeightChangedListener; @@ -825,6 +827,14 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro viewState.dump(pw, args); pw.println(); } + if (DUMP_VERBOSE) { + pw.println("mClipTopAmount: " + mClipTopAmount); + pw.println("mClipBottomAmount " + mClipBottomAmount); + pw.println("mClipToActualHeight: " + mClipToActualHeight); + pw.println("mExtraWidthForClipping: " + mExtraWidthForClipping); + pw.println("mMinimumHeightForClipping: " + mMinimumHeightForClipping); + pw.println("getClipBounds(): " + getClipBounds()); + } }); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java index 51715696efb0..da8d2d524456 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java @@ -28,12 +28,16 @@ import android.util.AttributeSet; import android.view.View; import com.android.internal.util.ArrayUtils; +import com.android.systemui.Dumpable; import com.android.systemui.R; +import java.io.PrintWriter; +import java.util.Arrays; + /** * A view that can be used for both the dimmed and normal background of an notification. */ -public class NotificationBackgroundView extends View { +public class NotificationBackgroundView extends View implements Dumpable { private final boolean mDontModifyCorners; private Drawable mBackground; @@ -42,7 +46,6 @@ public class NotificationBackgroundView extends View { private int mTintColor; private final float[] mCornerRadii = new float[8]; private boolean mBottomIsRounded; - private int mBackgroundTop; private boolean mBottomAmountClips = true; private int mActualHeight = -1; private int mActualWidth = -1; @@ -60,8 +63,7 @@ public class NotificationBackgroundView extends View { @Override protected void onDraw(Canvas canvas) { - if (mClipTopAmount + mClipBottomAmount < getActualHeight() - mBackgroundTop - || mExpandAnimationRunning) { + if (mClipTopAmount + mClipBottomAmount < getActualHeight() || mExpandAnimationRunning) { canvas.save(); if (!mExpandAnimationRunning) { canvas.clipRect(0, mClipTopAmount, getWidth(), @@ -74,7 +76,7 @@ public class NotificationBackgroundView extends View { private void draw(Canvas canvas, Drawable drawable) { if (drawable != null) { - int top = mBackgroundTop; + int top = 0; int bottom = getActualHeight(); if (mBottomIsRounded && mBottomAmountClips @@ -261,11 +263,6 @@ public class NotificationBackgroundView extends View { } } - public void setBackgroundTop(int backgroundTop) { - mBackgroundTop = backgroundTop; - invalidate(); - } - /** Set the current expand animation size. */ public void setExpandAnimationSize(int width, int height) { mExpandAnimationHeight = height; @@ -291,4 +288,16 @@ public class NotificationBackgroundView extends View { public void setPressedAllowed(boolean allowed) { mIsPressedAllowed = allowed; } + + @Override + public void dump(PrintWriter pw, String[] args) { + pw.println("mDontModifyCorners: " + mDontModifyCorners); + pw.println("mClipTopAmount: " + mClipTopAmount); + pw.println("mClipBottomAmount: " + mClipBottomAmount); + pw.println("mCornerRadii: " + Arrays.toString(mCornerRadii)); + pw.println("mBottomIsRounded: " + mBottomIsRounded); + pw.println("mBottomAmountClips: " + mBottomAmountClips); + pw.println("mActualWidth: " + mActualWidth); + pw.println("mActualHeight: " + mActualHeight); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java index 608bfa611ff0..924ae4a95fac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -45,8 +45,11 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.model.SysUiState; import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.util.DialogKt; import java.util.ArrayList; import java.util.List; @@ -68,6 +71,7 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh private static final boolean DEFAULT_DISMISS_ON_DEVICE_LOCK = true; private final Context mContext; + private final FeatureFlags mFeatureFlags; @Nullable private final DismissReceiver mDismissReceiver; private final Handler mHandler = new Handler(); private final SystemUIDialogManager mDialogManager; @@ -96,16 +100,23 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh // TODO(b/219008720): Remove those calls to Dependency.get by introducing a // SystemUIDialogFactory and make all other dialogs create a SystemUIDialog to which we set // the content and attach listeners. - this(context, theme, dismissOnDeviceLock, Dependency.get(SystemUIDialogManager.class), - Dependency.get(SysUiState.class), Dependency.get(BroadcastDispatcher.class), + this(context, theme, dismissOnDeviceLock, + Dependency.get(FeatureFlags.class), + Dependency.get(SystemUIDialogManager.class), + Dependency.get(SysUiState.class), + Dependency.get(BroadcastDispatcher.class), Dependency.get(DialogLaunchAnimator.class)); } public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock, - SystemUIDialogManager dialogManager, SysUiState sysUiState, - BroadcastDispatcher broadcastDispatcher, DialogLaunchAnimator dialogLaunchAnimator) { + FeatureFlags featureFlags, + SystemUIDialogManager dialogManager, + SysUiState sysUiState, + BroadcastDispatcher broadcastDispatcher, + DialogLaunchAnimator dialogLaunchAnimator) { super(context, theme); mContext = context; + mFeatureFlags = featureFlags; applyFlags(this); WindowManager.LayoutParams attrs = getWindow().getAttributes(); @@ -130,6 +141,12 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh for (int i = 0; i < mOnCreateRunnables.size(); i++) { mOnCreateRunnables.get(i).run(); } + if (mFeatureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM)) { + DialogKt.registerAnimationOnBackInvoked( + /* dialog = */ this, + /* targetView = */ getWindow().getDecorView() + ); + } } private void updateWindowSize() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt index 2d80edb8d2f4..270c592ae4fd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt @@ -21,7 +21,7 @@ import android.util.AttributeSet import android.widget.ImageView import android.widget.TextView import com.android.systemui.R -import com.android.systemui.common.ui.view.LaunchableLinearLayout +import com.android.systemui.animation.view.LaunchableLinearLayout class StatusBarUserSwitcherContainer( context: Context?, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt index 2f34516285cf..16c4027ef645 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.pipeline.mobile.data.model +import android.os.ParcelUuid + /** * SystemUI representation of [SubscriptionInfo]. Currently we only use two fields on the * subscriptions themselves: subscriptionId and isOpportunistic. Any new fields that we need can be @@ -29,4 +31,7 @@ data class SubscriptionModel( * filtering in certain cases. See [MobileIconsInteractor] for the filtering logic */ val isOpportunistic: Boolean = false, + + /** Subscriptions in the same group may be filtered or treated as a single subscription */ + val groupUuid: ParcelUuid? = null, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt index 938c7346f702..8f6a87b089f2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt @@ -28,8 +28,8 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetwork import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt index c9049d893f4a..73ce5e616b82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt @@ -52,8 +52,8 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConn import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import com.android.systemui.util.kotlin.pairwise import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher @@ -376,6 +376,7 @@ constructor( SubscriptionModel( subscriptionId = subscriptionId, isOpportunistic = isOpportunistic, + groupUuid = groupUuid, ) companion object { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt index 72d5113e5938..5a2e11e8de88 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt @@ -150,6 +150,12 @@ constructor( val info1 = unfilteredSubs[0] val info2 = unfilteredSubs[1] + + // Filtering only applies to subscriptions in the same group + if (info1.groupUuid == null || info1.groupUuid != info2.groupUuid) { + return@combine unfilteredSubs + } + // If both subscriptions are primary, show both if (!info1.isOpportunistic && !info2.isOpportunistic) { return@combine unfilteredSubs @@ -186,7 +192,7 @@ constructor( * validated bit from the old active network (A) while data is changing to the new one (B). * * This condition only applies if - * 1. A and B are in the same subscription group (e.c. for CBRS data switching) and + * 1. A and B are in the same subscription group (e.g. for CBRS data switching) and * 2. A was validated before the switch * * The goal of this is to minimize the flickering in the UI of the cellular indicator 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 index ac4d55c3a29c..08c14e743bb6 100644 --- 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 @@ -17,7 +17,7 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import kotlinx.coroutines.flow.StateFlow /** Provides data related to the wifi state. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt index 2cb81c809716..e0e0ed795e4a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt @@ -23,9 +23,9 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.demomode.DemoMode import com.android.systemui.demomode.DemoModeController import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt index a19c3c3e86a6..a4fbc2c93647 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt @@ -19,9 +19,9 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository.demo import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt index 5d4a6664a19a..86a668a2e842 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt @@ -18,8 +18,8 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt index c45b420780b9..7b486c1998cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt @@ -43,9 +43,9 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import java.util.concurrent.Executor import javax.inject.Inject import kotlinx.coroutines.CoroutineScope 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 index 86dcd18c643c..96ab074c6e56 100644 --- 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 @@ -21,8 +21,8 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow @@ -58,25 +58,29 @@ interface WifiInteractor { } @SysUISingleton -class WifiInteractorImpl @Inject constructor( +class WifiInteractorImpl +@Inject +constructor( connectivityRepository: ConnectivityRepository, wifiRepository: WifiRepository, ) : WifiInteractor { - override val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info -> - when (info) { - is WifiNetworkModel.Unavailable -> null - is WifiNetworkModel.Invalid -> null - is WifiNetworkModel.Inactive -> null - is WifiNetworkModel.CarrierMerged -> null - is WifiNetworkModel.Active -> when { - info.isPasspointAccessPoint || info.isOnlineSignUpForPasspointAccessPoint -> - info.passpointProviderFriendlyName - info.ssid != WifiManager.UNKNOWN_SSID -> info.ssid - else -> null + override val ssid: Flow<String?> = + wifiRepository.wifiNetwork.map { info -> + when (info) { + is WifiNetworkModel.Unavailable -> null + is WifiNetworkModel.Invalid -> null + is WifiNetworkModel.Inactive -> null + is WifiNetworkModel.CarrierMerged -> null + is WifiNetworkModel.Active -> + when { + info.isPasspointAccessPoint || info.isOnlineSignUpForPasspointAccessPoint -> + info.passpointProviderFriendlyName + info.ssid != WifiManager.UNKNOWN_SSID -> info.ssid + else -> null + } } } - } override val isEnabled: Flow<Boolean> = wifiRepository.isWifiEnabled @@ -86,7 +90,6 @@ class WifiInteractorImpl @Inject constructor( override val activity: StateFlow<DataActivityModel> = wifiRepository.wifiActivity - override val isForceHidden: Flow<Boolean> = connectivityRepository.forceHiddenSlots.map { - it.contains(ConnectivitySlot.WIFI) - } + override val isForceHidden: Flow<Boolean> = + connectivityRepository.forceHiddenSlots.map { it.contains(ConnectivitySlot.WIFI) } } 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/shared/model/WifiNetworkModel.kt index da2daf2c55ea..0923d7848d8c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt @@ -14,13 +14,13 @@ * limitations under the License. */ -package com.android.systemui.statusbar.pipeline.wifi.data.model +package com.android.systemui.statusbar.pipeline.wifi.shared.model -import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID +import android.telephony.SubscriptionManager import androidx.annotation.VisibleForTesting -import com.android.systemui.log.table.TableRowLogger import com.android.systemui.log.table.Diffable -import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS +import com.android.systemui.log.table.TableRowLogger +import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository /** Provides information about the current wifi network. */ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> { @@ -57,9 +57,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> { } } - /** - * A model representing that the wifi information we received was invalid in some way. - */ + /** A model representing that the wifi information we received was invalid in some way. */ data class Invalid( /** A description of why the wifi information was invalid. */ val invalidReason: String, @@ -142,21 +140,17 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> { */ val subscriptionId: Int, - /** - * The signal level, guaranteed to be 0 <= level <= numberOfLevels. - */ + /** The signal level, guaranteed to be 0 <= level <= numberOfLevels. */ val level: Int, - /** - * The maximum possible level. - */ - val numberOfLevels: Int = DEFAULT_NUM_LEVELS, + /** The maximum possible level. */ + val numberOfLevels: Int = MobileConnectionRepository.DEFAULT_NUM_LEVELS, ) : WifiNetworkModel() { init { require(level in MIN_VALID_LEVEL..numberOfLevels) { "0 <= wifi level <= $numberOfLevels required; level was $level" } - require(subscriptionId != INVALID_SUBSCRIPTION_ID) { + require(subscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { "subscription ID cannot be invalid" } } @@ -208,9 +202,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> { /** See [android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED]. */ val isValidated: Boolean = false, - /** - * The wifi signal level, guaranteed to be 0 <= level <= 4. - */ + /** The wifi signal level, guaranteed to be 0 <= level <= 4. */ val level: Int, /** See [android.net.wifi.WifiInfo.ssid]. */ @@ -255,8 +247,10 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> { if (prevVal.isPasspointAccessPoint != isPasspointAccessPoint) { row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint) } - if (prevVal.isOnlineSignUpForPasspointAccessPoint != - isOnlineSignUpForPasspointAccessPoint) { + if ( + prevVal.isOnlineSignUpForPasspointAccessPoint != + isOnlineSignUpForPasspointAccessPoint + ) { row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint) } if (prevVal.passpointProviderFriendlyName != passpointProviderFriendlyName) { @@ -281,29 +275,29 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> { // Only include the passpoint-related values in the string if we have them. (Most // networks won't have them so they'll be mostly clutter.) val passpointString = - if (isPasspointAccessPoint || - isOnlineSignUpForPasspointAccessPoint || - passpointProviderFriendlyName != null) { + if ( + isPasspointAccessPoint || + isOnlineSignUpForPasspointAccessPoint || + passpointProviderFriendlyName != null + ) { ", isPasspointAp=$isPasspointAccessPoint, " + "isOnlineSignUpForPasspointAp=$isOnlineSignUpForPasspointAccessPoint, " + "passpointName=$passpointProviderFriendlyName" - } else { - "" - } + } else { + "" + } return "WifiNetworkModel.Active(networkId=$networkId, isValidated=$isValidated, " + "level=$level, ssid=$ssid$passpointString)" } companion object { - @VisibleForTesting - internal const val MAX_VALID_LEVEL = 4 + @VisibleForTesting internal const val MAX_VALID_LEVEL = 4 } } companion object { - @VisibleForTesting - internal const val MIN_VALID_LEVEL = 0 + @VisibleForTesting internal const val MIN_VALID_LEVEL = 0 } } 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 index 95431afb71bb..0f5ff91866fa 100644 --- 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 @@ -25,8 +25,6 @@ import com.android.systemui.R import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog -import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS @@ -34,13 +32,15 @@ import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_IC import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel +import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow @@ -55,15 +55,12 @@ import kotlinx.coroutines.flow.stateIn /** * Models the UI state for the status bar wifi icon. * - * This class exposes three view models, one per status bar location: - * - [home] - * - [keyguard] - * - [qs] - * In order to get the UI state for the wifi icon, you must use one of those view models (whichever - * is correct for your location). + * This class exposes three view models, one per status bar location: [home], [keyguard], and [qs]. + * In order to get the UI state for the wifi icon, you must use one of those view models (whichever + * is correct for your location). * - * Internally, this class maintains the current state of the wifi icon and notifies those three - * view models of any changes. + * Internally, this class maintains the current state of the wifi icon and notifies those three view + * models of any changes. */ @SysUISingleton class WifiViewModel @@ -85,12 +82,13 @@ constructor( is WifiNetworkModel.Unavailable -> WifiIcon.Hidden is WifiNetworkModel.Invalid -> WifiIcon.Hidden is WifiNetworkModel.CarrierMerged -> WifiIcon.Hidden - is WifiNetworkModel.Inactive -> WifiIcon.Visible( - res = WIFI_NO_NETWORK, - ContentDescription.Loaded( - "${context.getString(WIFI_NO_CONNECTION)},${context.getString(NO_INTERNET)}" + is WifiNetworkModel.Inactive -> + WifiIcon.Visible( + res = WIFI_NO_NETWORK, + ContentDescription.Loaded( + "${context.getString(WIFI_NO_CONNECTION)},${context.getString(NO_INTERNET)}" + ) ) - ) is WifiNetworkModel.Active -> { val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[this.level]) when { @@ -114,25 +112,25 @@ constructor( /** The wifi icon that should be displayed. */ private val wifiIcon: StateFlow<WifiIcon> = combine( - interactor.isEnabled, - interactor.isDefault, - interactor.isForceHidden, - interactor.wifiNetwork, - ) { isEnabled, isDefault, isForceHidden, wifiNetwork -> - if (!isEnabled || isForceHidden || wifiNetwork is WifiNetworkModel.CarrierMerged) { - return@combine WifiIcon.Hidden - } + interactor.isEnabled, + interactor.isDefault, + interactor.isForceHidden, + interactor.wifiNetwork, + ) { isEnabled, isDefault, isForceHidden, wifiNetwork -> + if (!isEnabled || isForceHidden || wifiNetwork is WifiNetworkModel.CarrierMerged) { + return@combine WifiIcon.Hidden + } - val icon = wifiNetwork.icon() + val icon = wifiNetwork.icon() - return@combine when { - isDefault -> icon - wifiConstants.alwaysShowIconIfEnabled -> icon - !connectivityConstants.hasDataCapabilities -> icon - wifiNetwork is WifiNetworkModel.Active && wifiNetwork.isValidated -> icon - else -> WifiIcon.Hidden + return@combine when { + isDefault -> icon + wifiConstants.alwaysShowIconIfEnabled -> icon + !connectivityConstants.hasDataCapabilities -> icon + wifiNetwork is WifiNetworkModel.Active && wifiNetwork.isValidated -> icon + else -> WifiIcon.Hidden + } } - } .logDiffsForTable( wifiTableLogBuffer, columnPrefix = "", @@ -147,34 +145,34 @@ constructor( /** The wifi activity status. Null if we shouldn't display the activity status. */ private val activity: Flow<DataActivityModel?> = if (!connectivityConstants.shouldShowActivityConfig) { - flowOf(null) - } else { - combine(interactor.activity, interactor.ssid) { activity, ssid -> - when (ssid) { - null -> null - else -> activity + flowOf(null) + } else { + combine(interactor.activity, interactor.ssid) { activity, ssid -> + when (ssid) { + null -> null + else -> activity + } } } - } - .distinctUntilChanged() - .logOutputChange(logger, "activity") - .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null) + .distinctUntilChanged() + .logOutputChange(logger, "activity") + .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null) private val isActivityInViewVisible: Flow<Boolean> = - activity - .map { it?.hasActivityIn == true } - .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false) + activity + .map { it?.hasActivityIn == true } + .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false) private val isActivityOutViewVisible: Flow<Boolean> = - activity - .map { it?.hasActivityOut == true } - .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false) + activity + .map { it?.hasActivityOut == true } + .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false) private val isActivityContainerVisible: Flow<Boolean> = - combine(isActivityInViewVisible, isActivityOutViewVisible) { activityIn, activityOut -> - activityIn || activityOut - } - .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false) + combine(isActivityInViewVisible, isActivityOutViewVisible) { activityIn, activityOut -> + activityIn || activityOut + } + .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false) // TODO(b/238425913): It isn't ideal for the wifi icon to need to know about whether the // airplane icon is visible. Instead, we should have a parent StatusBarSystemIconsViewModel diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt new file mode 100644 index 000000000000..2a18b8149637 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use mHost file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT 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.policy + +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tiles.AlarmTile +import com.android.systemui.qs.tiles.CameraToggleTile +import com.android.systemui.qs.tiles.DndTile +import com.android.systemui.qs.tiles.FlashlightTile +import com.android.systemui.qs.tiles.LocationTile +import com.android.systemui.qs.tiles.MicrophoneToggleTile +import com.android.systemui.qs.tiles.UiModeNightTile +import com.android.systemui.qs.tiles.WorkModeTile +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import dagger.multibindings.StringKey + +@Module +interface PolicyModule { + + /** Inject DndTile into tileMap in QSModule */ + @Binds @IntoMap @StringKey(DndTile.TILE_SPEC) fun bindDndTile(dndTile: DndTile): QSTileImpl<*> + + /** Inject WorkModeTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(WorkModeTile.TILE_SPEC) + fun bindWorkModeTile(workModeTile: WorkModeTile): QSTileImpl<*> + + /** Inject FlashlightTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(FlashlightTile.TILE_SPEC) + fun bindFlashlightTile(flashlightTile: FlashlightTile): QSTileImpl<*> + + /** Inject LocationTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(LocationTile.TILE_SPEC) + fun bindLocationTile(locationTile: LocationTile): QSTileImpl<*> + + /** Inject CameraToggleTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(CameraToggleTile.TILE_SPEC) + fun bindCameraToggleTile(cameraToggleTile: CameraToggleTile): QSTileImpl<*> + + /** Inject MicrophoneToggleTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(MicrophoneToggleTile.TILE_SPEC) + fun bindMicrophoneToggleTile(microphoneToggleTile: MicrophoneToggleTile): QSTileImpl<*> + + /** Inject AlarmTile into tileMap in QSModule */ + @Binds + @IntoMap + @StringKey(AlarmTile.TILE_SPEC) + fun bindAlarmTile(alarmTile: AlarmTile): QSTileImpl<*> + + @Binds + @IntoMap + @StringKey(UiModeNightTile.TILE_SPEC) + fun bindUiModeNightTile(uiModeNightTile: UiModeNightTile): QSTileImpl<*> +} diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt index 696134cde3c9..a20a5b2fdbbc 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt @@ -16,6 +16,8 @@ package com.android.systemui.temporarydisplay.chipbar +import android.animation.ObjectAnimator +import android.animation.ValueAnimator import android.content.Context import android.graphics.Rect import android.os.PowerManager @@ -27,11 +29,14 @@ import android.view.View.ACCESSIBILITY_LIVE_REGION_NONE import android.view.ViewGroup import android.view.WindowManager import android.view.accessibility.AccessibilityManager +import android.widget.ImageView import android.widget.TextView import androidx.annotation.IdRes +import androidx.annotation.VisibleForTesting import com.android.internal.widget.CachingIconView import com.android.systemui.Gefingerpoken import com.android.systemui.R +import com.android.systemui.animation.Interpolators import com.android.systemui.classifier.FalsingCollector import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription import com.android.systemui.common.shared.model.Text.Companion.loadText @@ -101,6 +106,15 @@ constructor( private lateinit var parent: ChipbarRootView + /** The current loading information, or null we're not currently loading. */ + @VisibleForTesting + internal var loadingDetails: LoadingDetails? = null + private set(value) { + // Always cancel the old one before updating + field?.animator?.cancel() + field = value + } + override val windowLayoutParams = commonWindowLayoutParams.apply { gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL) } @@ -143,8 +157,22 @@ constructor( // ---- End item ---- // Loading - currentView.requireViewById<View>(R.id.loading).visibility = - (newInfo.endItem == ChipbarEndItem.Loading).visibleIfTrue() + val isLoading = newInfo.endItem == ChipbarEndItem.Loading + val loadingView = currentView.requireViewById<ImageView>(R.id.loading) + loadingView.visibility = isLoading.visibleIfTrue() + + if (isLoading) { + val currentLoadingDetails = loadingDetails + // Since there can be multiple chipbars, we need to check if the loading view is the + // same and possibly re-start the loading animation on the new view. + if (currentLoadingDetails == null || currentLoadingDetails.loadingView != loadingView) { + val newDetails = createLoadingDetails(loadingView) + newDetails.animator.start() + loadingDetails = newDetails + } + } else { + loadingDetails = null + } // Error currentView.requireViewById<View>(R.id.error).visibility = @@ -223,12 +251,17 @@ constructor( override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) { val innerView = view.getInnerView() innerView.accessibilityLiveRegion = ACCESSIBILITY_LIVE_REGION_NONE - val removed = chipbarAnimator.animateViewOut(innerView, onAnimationEnd) + + val fullEndRunnable = Runnable { + loadingDetails = null + onAnimationEnd.run() + } + val removed = chipbarAnimator.animateViewOut(innerView, fullEndRunnable) // If the view doesn't get animated, the [onAnimationEnd] runnable won't get run. So, just // run it immediately. if (!removed) { logger.logAnimateOutFailure() - onAnimationEnd.run() + fullEndRunnable.run() } updateGestureListening() @@ -269,7 +302,7 @@ constructor( } private fun ViewGroup.getInnerView(): ViewGroup { - return requireViewById(R.id.chipbar_inner) + return this.requireViewById(R.id.chipbar_inner) } override fun getTouchableRegion(view: View, outRect: Rect) { @@ -283,8 +316,28 @@ constructor( View.GONE } } + + private fun createLoadingDetails(loadingView: View): LoadingDetails { + // Ideally, we would use a <ProgressBar> view, which would automatically handle the loading + // spinner rotation for us. However, due to b/243983980, the ProgressBar animation + // unexpectedly pauses when SysUI starts another window. ObjectAnimator is a workaround that + // won't pause. + val animator = + ObjectAnimator.ofFloat(loadingView, View.ROTATION, 0f, 360f).apply { + duration = LOADING_ANIMATION_DURATION_MS + repeatCount = ValueAnimator.INFINITE + interpolator = Interpolators.LINEAR + } + return LoadingDetails(loadingView, animator) + } + + internal data class LoadingDetails( + val loadingView: View, + val animator: ObjectAnimator, + ) } @IdRes private val INFO_TAG = R.id.tag_chipbar_info private const val SWIPE_UP_GESTURE_REASON = "SWIPE_UP_GESTURE_DETECTED" private const val TAG = "ChipbarCoordinator" +private const val LOADING_ANIMATION_DURATION_MS = 1000L diff --git a/packages/SystemUI/src/com/android/systemui/user/UserModule.java b/packages/SystemUI/src/com/android/systemui/user/UserModule.java index 2b29885db682..f7c8bac1b478 100644 --- a/packages/SystemUI/src/com/android/systemui/user/UserModule.java +++ b/packages/SystemUI/src/com/android/systemui/user/UserModule.java @@ -21,6 +21,7 @@ import android.os.UserHandle; import com.android.settingslib.users.EditUserInfoController; import com.android.systemui.user.data.repository.UserRepositoryModule; +import com.android.systemui.user.domain.interactor.HeadlessSystemUserModeModule; import com.android.systemui.user.ui.dialog.UserDialogModule; import dagger.Binds; @@ -36,6 +37,7 @@ import dagger.multibindings.IntoMap; includes = { UserDialogModule.class, UserRepositoryModule.class, + HeadlessSystemUserModeModule.class, } ) public abstract class UserModule { diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserMode.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserMode.kt new file mode 100644 index 000000000000..756e6a1a5b15 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserMode.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.user.domain.interactor + +import android.os.UserManager +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +interface HeadlessSystemUserMode { + + fun isHeadlessSystemUserMode(): Boolean +} + +@SysUISingleton +class HeadlessSystemUserModeImpl @Inject constructor() : HeadlessSystemUserMode { + override fun isHeadlessSystemUserMode(): Boolean { + return UserManager.isHeadlessSystemUserMode() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeModule.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeModule.kt new file mode 100644 index 000000000000..0efa2d8b6a36 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeModule.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.user.domain.interactor + +import dagger.Binds + +@dagger.Module +interface HeadlessSystemUserModeModule { + + @Binds + fun bindIsHeadlessSystemUserMode(impl: HeadlessSystemUserModeImpl): HeadlessSystemUserMode +} diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt index c0ba3cc352b0..3f895ad0b5b4 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt @@ -86,6 +86,7 @@ constructor( private val keyguardInteractor: KeyguardInteractor, private val featureFlags: FeatureFlags, private val manager: UserManager, + private val headlessSystemUserMode: HeadlessSystemUserMode, @Application private val applicationScope: CoroutineScope, telephonyInteractor: TelephonyInteractor, broadcastDispatcher: BroadcastDispatcher, @@ -560,7 +561,10 @@ constructor( actionType = action, isRestricted = isRestricted, isSwitchToEnabled = - canSwitchUsers(selectedUserId) && + canSwitchUsers( + selectedUserId = selectedUserId, + isAction = true, + ) && // If the user is auto-created is must not be currently resetting. !(isGuestUserAutoCreated && isGuestUserResetting), ) @@ -712,10 +716,32 @@ constructor( } } - private suspend fun canSwitchUsers(selectedUserId: Int): Boolean { - return withContext(backgroundDispatcher) { - manager.getUserSwitchability(UserHandle.of(selectedUserId)) - } == UserManager.SWITCHABILITY_STATUS_OK + private suspend fun canSwitchUsers( + selectedUserId: Int, + isAction: Boolean = false, + ): Boolean { + val isHeadlessSystemUserMode = + withContext(backgroundDispatcher) { headlessSystemUserMode.isHeadlessSystemUserMode() } + // Whether menu item should be active. True if item is a user or if any user has + // signed in since reboot or in all cases for non-headless system user mode. + val isItemEnabled = !isAction || !isHeadlessSystemUserMode || isAnyUserUnlocked() + return isItemEnabled && + withContext(backgroundDispatcher) { + manager.getUserSwitchability(UserHandle.of(selectedUserId)) + } == UserManager.SWITCHABILITY_STATUS_OK + } + + private suspend fun isAnyUserUnlocked(): Boolean { + return manager + .getUsers( + /* excludePartial= */ true, + /* excludeDying= */ true, + /* excludePreCreated= */ true + ) + .any { user -> + user.id != UserHandle.USER_SYSTEM && + withContext(backgroundDispatcher) { manager.isUserUnlocked(user.userHandle) } + } } @SuppressLint("UseCompatLoadingForDrawables") diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java b/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java index b41bca0d77e1..8d32a4833471 100644 --- a/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java +++ b/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java @@ -43,11 +43,6 @@ public abstract class ConditionalCoreStartable implements CoreStartable { @Override public final void start() { - if (mConditionSet == null || mConditionSet.isEmpty()) { - onStart(); - return; - } - mStartToken = mMonitor.addSubscription( new Monitor.Subscription.Builder(allConditionsMet -> { if (allConditionsMet) { @@ -63,11 +58,6 @@ public abstract class ConditionalCoreStartable implements CoreStartable { @Override public final void onBootCompleted() { - if (mConditionSet == null || mConditionSet.isEmpty()) { - bootCompleted(); - return; - } - mBootCompletedToken = mMonitor.addSubscription( new Monitor.Subscription.Builder(allConditionsMet -> { if (allConditionsMet) { diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitorModule.kt b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitorModule.kt new file mode 100644 index 000000000000..c74e71f668f8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitorModule.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.leak + +import com.android.systemui.CoreStartable +import com.android.systemui.qs.tileimpl.QSTileImpl +import dagger.Binds +import dagger.Module +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap +import dagger.multibindings.StringKey + +@Module +interface GarbageMonitorModule { + /** Inject into GarbageMonitor.Service. */ + @Binds + @IntoMap + @ClassKey(GarbageMonitor::class) + fun bindGarbageMonitorService(sysui: GarbageMonitor.Service): CoreStartable + + @Binds + @IntoMap + @StringKey(GarbageMonitor.MemoryTile.TILE_SPEC) + fun bindMemoryTile(memoryTile: GarbageMonitor.MemoryTile): QSTileImpl<*> +} diff --git a/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java b/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java index 2c901d285939..9429d8991090 100644 --- a/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java +++ b/packages/SystemUI/src/com/android/systemui/wallet/dagger/WalletModule.java @@ -22,6 +22,8 @@ import android.service.quickaccesswallet.QuickAccessWalletClient; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.qs.tiles.QuickAccessWalletTile; import com.android.systemui.wallet.ui.WalletActivity; import java.util.concurrent.Executor; @@ -31,6 +33,7 @@ import dagger.Module; import dagger.Provides; import dagger.multibindings.ClassKey; import dagger.multibindings.IntoMap; +import dagger.multibindings.StringKey; /** @@ -52,4 +55,11 @@ public abstract class WalletModule { @Background Executor bgExecutor) { return QuickAccessWalletClient.create(context, bgExecutor); } + + /** */ + @Binds + @IntoMap + @StringKey(QuickAccessWalletTile.TILE_SPEC) + public abstract QSTileImpl<?> bindQuickAccessWalletTile( + QuickAccessWalletTile quickAccessWalletTile); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt index e8d50ca4bc76..badeb27e7696 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt @@ -24,13 +24,19 @@ import android.os.Handler import android.os.PowerManager import android.os.PowerManager.WAKE_REASON_BIOMETRIC import android.os.UserHandle -import android.provider.Settings +import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL +import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO +import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS +import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT +import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED +import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_WAKE +import android.provider.Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq -import com.android.systemui.util.settings.SecureSettings +import com.android.systemui.util.settings.FakeSettings import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before @@ -41,20 +47,11 @@ import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations +import java.io.PrintWriter @SmallTest class ActiveUnlockConfigTest : SysuiTestCase() { - private val fakeWakeUri = Uri.Builder().appendPath("wake").build() - private val fakeUnlockIntentUri = Uri.Builder().appendPath("unlock-intent").build() - private val fakeBioFailUri = Uri.Builder().appendPath("bio-fail").build() - private val fakeFaceErrorsUri = Uri.Builder().appendPath("face-errors").build() - private val fakeFaceAcquiredUri = Uri.Builder().appendPath("face-acquired").build() - private val fakeUnlockIntentBioEnroll = Uri.Builder().appendPath("unlock-intent-bio").build() - private val fakeWakeupsConsideredUnlockIntents = - Uri.Builder().appendPath("wakeups-considered-unlock-intent").build() - - @Mock - private lateinit var secureSettings: SecureSettings + private lateinit var secureSettings: FakeSettings @Mock private lateinit var contentResolver: ContentResolver @Mock @@ -63,33 +60,20 @@ class ActiveUnlockConfigTest : SysuiTestCase() { private lateinit var dumpManager: DumpManager @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + @Mock private lateinit var mockPrintWriter: PrintWriter @Captor private lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver> private lateinit var activeUnlockConfig: ActiveUnlockConfig + private var currentUser: Int = 0 @Before fun setUp() { MockitoAnnotations.initMocks(this) - `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_WAKE)) - .thenReturn(fakeWakeUri) - `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT)) - .thenReturn(fakeUnlockIntentUri) - `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)) - .thenReturn(fakeBioFailUri) - `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS)) - .thenReturn(fakeFaceErrorsUri) - `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO)) - .thenReturn(fakeFaceAcquiredUri) - `when`(secureSettings.getUriFor( - Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED)) - .thenReturn(fakeUnlockIntentBioEnroll) - `when`(secureSettings.getUriFor( - Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS)) - .thenReturn(fakeWakeupsConsideredUnlockIntents) - + currentUser = KeyguardUpdateMonitor.getCurrentUser() + secureSettings = FakeSettings() activeUnlockConfig = ActiveUnlockConfig( handler, secureSettings, @@ -105,8 +89,6 @@ class ActiveUnlockConfigTest : SysuiTestCase() { @Test fun onWakeupSettingChanged() { - verifyRegisterSettingObserver() - // GIVEN no active unlock settings enabled assertFalse( activeUnlockConfig.shouldAllowActiveUnlockFromOrigin( @@ -114,9 +96,8 @@ class ActiveUnlockConfigTest : SysuiTestCase() { ) // WHEN unlock on wake is allowed - `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_WAKE, - 0, 0)).thenReturn(1) - updateSetting(fakeWakeUri) + secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_WAKE, 1, currentUser) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE)) // THEN active unlock triggers allowed on: wake, unlock-intent, and biometric failure assertTrue( @@ -135,8 +116,6 @@ class ActiveUnlockConfigTest : SysuiTestCase() { @Test fun onUnlockIntentSettingChanged() { - verifyRegisterSettingObserver() - // GIVEN no active unlock settings enabled assertFalse( activeUnlockConfig.shouldAllowActiveUnlockFromOrigin( @@ -144,9 +123,8 @@ class ActiveUnlockConfigTest : SysuiTestCase() { ) // WHEN unlock on biometric failed is allowed - `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT, - 0, 0)).thenReturn(1) - updateSetting(fakeUnlockIntentUri) + secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_UNLOCK_INTENT, 1, currentUser) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT)) // THEN active unlock triggers allowed on: biometric failure ONLY assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin( @@ -159,21 +137,19 @@ class ActiveUnlockConfigTest : SysuiTestCase() { @Test fun onBioFailSettingChanged() { - verifyRegisterSettingObserver() - // GIVEN no active unlock settings enabled and triggering unlock intent on biometric // enrollment setting is disabled (empty string is disabled, null would use the default) - `when`(secureSettings.getStringForUser( - Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED, - 0)).thenReturn("") - updateSetting(fakeUnlockIntentBioEnroll) + secureSettings.putStringForUser( + ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED, "", currentUser) + updateSetting(secureSettings.getUriFor( + ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED + )) assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin( ActiveUnlockConfig.ActiveUnlockRequestOrigin.BIOMETRIC_FAIL)) // WHEN unlock on biometric failed is allowed - `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, - 0, 0)).thenReturn(1) - updateSetting(fakeBioFailUri) + secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)) // THEN active unlock triggers allowed on: biometric failure ONLY assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin( @@ -186,17 +162,14 @@ class ActiveUnlockConfigTest : SysuiTestCase() { @Test fun faceErrorSettingsChanged() { - verifyRegisterSettingObserver() - // GIVEN unlock on biometric fail - `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, - 0, 0)).thenReturn(1) - updateSetting(fakeBioFailUri) + secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)) // WHEN face error timeout (3), allow trigger active unlock - `when`(secureSettings.getStringForUser(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS, - 0)).thenReturn("3") - updateSetting(fakeFaceAcquiredUri) + secureSettings.putStringForUser( + ACTIVE_UNLOCK_ON_FACE_ERRORS, "3", currentUser) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ERRORS)) // THEN active unlock triggers allowed on error TIMEOUT assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceError( @@ -208,19 +181,17 @@ class ActiveUnlockConfigTest : SysuiTestCase() { @Test fun faceAcquiredSettingsChanged() { - verifyRegisterSettingObserver() - // GIVEN unlock on biometric fail - `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, - 0, 0)).thenReturn(1) - updateSetting(fakeBioFailUri) + secureSettings.putStringForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, "1", currentUser) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)) // WHEN face acquiredMsg DARK_GLASSESand MOUTH_COVERING are allowed to trigger - `when`(secureSettings.getStringForUser(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO, - 0)).thenReturn( + secureSettings.putStringForUser( + ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO, "${BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED}" + - "|${BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED}") - updateSetting(fakeFaceAcquiredUri) + "|${BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED}", + currentUser) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO)) // THEN active unlock triggers allowed on acquired messages DARK_GLASSES & MOUTH_COVERING assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo( @@ -236,23 +207,23 @@ class ActiveUnlockConfigTest : SysuiTestCase() { @Test fun triggerOnUnlockIntentWhenBiometricEnrolledNone() { - verifyRegisterSettingObserver() - // GIVEN unlock on biometric fail - `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, - 0, 0)).thenReturn(1) - updateSetting(fakeBioFailUri) + secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)) // GIVEN fingerprint and face are NOT enrolled activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor - `when`(keyguardUpdateMonitor.isFaceEnrolled()).thenReturn(false) + `when`(keyguardUpdateMonitor.isFaceEnrolled).thenReturn(false) `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(false) // WHEN unlock intent is allowed when NO biometrics are enrolled (0) - `when`(secureSettings.getStringForUser( - Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED, - 0)).thenReturn("${ActiveUnlockConfig.BiometricType.NONE.intValue}") - updateSetting(fakeUnlockIntentBioEnroll) + + secureSettings.putStringForUser( + ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED, + "${ActiveUnlockConfig.BiometricType.NONE.intValue}", currentUser) + updateSetting(secureSettings.getUriFor( + ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED + )) // THEN active unlock triggers allowed on unlock intent assertTrue(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin( @@ -261,12 +232,9 @@ class ActiveUnlockConfigTest : SysuiTestCase() { @Test fun triggerOnUnlockIntentWhenBiometricEnrolledFingerprintOrFaceOnly() { - verifyRegisterSettingObserver() - // GIVEN unlock on biometric fail - `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, - 0, 0)).thenReturn(1) - updateSetting(fakeBioFailUri) + secureSettings.putIntForUser(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 1, currentUser) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)) // GIVEN fingerprint and face are both enrolled activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor @@ -275,12 +243,14 @@ class ActiveUnlockConfigTest : SysuiTestCase() { // WHEN unlock intent is allowed when ONLY fingerprint is enrolled or NO biometircs // are enrolled - `when`(secureSettings.getStringForUser( - Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED, - 0)).thenReturn( + secureSettings.putStringForUser( + ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED, "${ActiveUnlockConfig.BiometricType.ANY_FACE.intValue}" + - "|${ActiveUnlockConfig.BiometricType.ANY_FINGERPRINT.intValue}") - updateSetting(fakeUnlockIntentBioEnroll) + "|${ActiveUnlockConfig.BiometricType.ANY_FINGERPRINT.intValue}", + currentUser) + updateSetting(secureSettings.getUriFor( + ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED + )) // THEN active unlock triggers NOT allowed on unlock intent assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin( @@ -305,13 +275,12 @@ class ActiveUnlockConfigTest : SysuiTestCase() { @Test fun isWakeupConsideredUnlockIntent_singleValue() { - verifyRegisterSettingObserver() - // GIVEN lift is considered an unlock intent - `when`(secureSettings.getStringForUser( - Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS, - 0)).thenReturn(PowerManager.WAKE_REASON_LIFT.toString()) - updateSetting(fakeWakeupsConsideredUnlockIntents) + secureSettings.putIntForUser( + ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS, + PowerManager.WAKE_REASON_LIFT, + currentUser) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS)) // THEN only WAKE_REASON_LIFT is considered an unlock intent for (wakeReason in 0..WAKE_REASON_BIOMETRIC) { @@ -325,17 +294,15 @@ class ActiveUnlockConfigTest : SysuiTestCase() { @Test fun isWakeupConsideredUnlockIntent_multiValue() { - verifyRegisterSettingObserver() - // GIVEN lift and tap are considered an unlock intent - `when`(secureSettings.getStringForUser( - Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS, - 0)).thenReturn( + secureSettings.putStringForUser( + ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS, PowerManager.WAKE_REASON_LIFT.toString() + "|" + - PowerManager.WAKE_REASON_TAP.toString() + PowerManager.WAKE_REASON_TAP.toString(), + currentUser ) - updateSetting(fakeWakeupsConsideredUnlockIntents) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS)) // THEN WAKE_REASON_LIFT and WAKE_REASON TAP are considered an unlock intent for (wakeReason in 0..WAKE_REASON_BIOMETRIC) { @@ -354,13 +321,10 @@ class ActiveUnlockConfigTest : SysuiTestCase() { @Test fun isWakeupConsideredUnlockIntent_emptyValues() { - verifyRegisterSettingObserver() - // GIVEN lift and tap are considered an unlock intent - `when`(secureSettings.getStringForUser( - Settings.Secure.ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS, - 0)).thenReturn(" ") - updateSetting(fakeWakeupsConsideredUnlockIntents) + secureSettings.putStringForUser(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS, " ", + currentUser) + updateSetting(secureSettings.getUriFor(ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS)) // THEN no wake up gestures are considered an unlock intent for (wakeReason in 0..WAKE_REASON_BIOMETRIC) { @@ -373,7 +337,23 @@ class ActiveUnlockConfigTest : SysuiTestCase() { PowerManager.WAKE_REASON_UNFOLD_DEVICE)) } + @Test + fun dump_onUnlockIntentWhenBiometricEnrolled_invalidNum_noArrayOutOfBoundsException() { + // GIVEN an invalid input (-1) + secureSettings.putStringForUser(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED, + "-1", currentUser) + + // WHEN the setting updates + updateSetting(secureSettings.getUriFor( + ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED + )) + + // THEN no exception thrown + activeUnlockConfig.dump(mockPrintWriter, emptyArray()) + } + private fun updateSetting(uri: Uri) { + verifyRegisterSettingObserver() settingsObserverCaptor.value.onChange( false, listOf(uri), @@ -383,13 +363,17 @@ class ActiveUnlockConfigTest : SysuiTestCase() { } private fun verifyRegisterSettingObserver() { - verifyRegisterSettingObserver(fakeWakeUri) - verifyRegisterSettingObserver(fakeUnlockIntentUri) - verifyRegisterSettingObserver(fakeBioFailUri) - verifyRegisterSettingObserver(fakeFaceErrorsUri) - verifyRegisterSettingObserver(fakeFaceAcquiredUri) - verifyRegisterSettingObserver(fakeUnlockIntentBioEnroll) - verifyRegisterSettingObserver(fakeWakeupsConsideredUnlockIntents) + verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE)) + verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT)) + verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)) + verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ERRORS)) + verifyRegisterSettingObserver(secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO)) + verifyRegisterSettingObserver(secureSettings.getUriFor( + ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED + )) + verifyRegisterSettingObserver(secureSettings.getUriFor( + ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS + )) } private fun verifyRegisterSettingObserver(uri: Uri) { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index 8dc1e8fba600..254f9531ef83 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -16,7 +16,6 @@ package com.android.keyguard; -import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static com.android.keyguard.KeyguardClockSwitch.LARGE; @@ -190,7 +189,6 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1); assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE); assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0); - assertThat(mSmallClockFrame.getVisibility()).isEqualTo(INVISIBLE); } @Test @@ -200,7 +198,6 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { assertThat(mLargeClockFrame.getAlpha()).isEqualTo(1); assertThat(mLargeClockFrame.getVisibility()).isEqualTo(VISIBLE); assertThat(mSmallClockFrame.getAlpha()).isEqualTo(0); - assertThat(mSmallClockFrame.getVisibility()).isEqualTo(INVISIBLE); } @Test @@ -215,7 +212,6 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { // only big clock is removed at switch assertThat(mLargeClockFrame.getParent()).isNull(); assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0); - assertThat(mLargeClockFrame.getVisibility()).isEqualTo(INVISIBLE); } @Test @@ -227,7 +223,6 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { // only big clock is removed at switch assertThat(mLargeClockFrame.getParent()).isNull(); assertThat(mLargeClockFrame.getAlpha()).isEqualTo(0); - assertThat(mLargeClockFrame.getVisibility()).isEqualTo(INVISIBLE); } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt new file mode 100644 index 000000000000..9fcb9c8f1662 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.keyguard + +import android.graphics.drawable.Drawable +import android.graphics.drawable.GradientDrawable +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.anyFloat +import org.mockito.Mockito.never +import org.mockito.Mockito.reset +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class NumPadAnimatorTest : SysuiTestCase() { + @Mock lateinit var background: GradientDrawable + @Mock lateinit var buttonImage: Drawable + private lateinit var underTest: NumPadAnimator + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + underTest = NumPadAnimator(context, background, 0, buttonImage) + } + + @Test + fun testOnLayout() { + underTest.onLayout(100) + verify(background).cornerRadius = 50f + reset(background) + underTest.onLayout(100) + verify(background, never()).cornerRadius = anyFloat() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt new file mode 100644 index 000000000000..777dd4e0b4a3 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.accessibility.fontscaling + +import android.os.Handler +import android.provider.Settings +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.widget.ImageView +import android.widget.SeekBar +import androidx.test.filters.SmallTest +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView +import com.android.systemui.util.settings.FakeSettings +import com.android.systemui.util.settings.SystemSettings +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +/** Tests for [FontScalingDialog]. */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +class FontScalingDialogTest : SysuiTestCase() { + private lateinit var fontScalingDialog: FontScalingDialog + private lateinit var systemSettings: SystemSettings + private val fontSizeValueArray: Array<String> = + mContext + .getResources() + .getStringArray(com.android.settingslib.R.array.entryvalues_font_size) + + @Before + fun setUp() { + val mainHandler = Handler(TestableLooper.get(this).getLooper()) + systemSettings = FakeSettings() + fontScalingDialog = FontScalingDialog(mContext, systemSettings as FakeSettings) + } + + @Test + fun showTheDialog_seekbarIsShowingCorrectProgress() { + fontScalingDialog.show() + + val seekBar: SeekBar = fontScalingDialog.findViewById<SeekBar>(R.id.seekbar)!! + val progress: Int = seekBar.getProgress() + val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f) + + assertThat(currentScale).isEqualTo(fontSizeValueArray[progress].toFloat()) + + fontScalingDialog.dismiss() + } + + @Test + fun progressIsZero_clickIconEnd_seekBarProgressIncreaseOne_fontSizeScaled() { + fontScalingDialog.show() + + val iconEnd: ImageView = fontScalingDialog.findViewById(R.id.icon_end)!! + val seekBarWithIconButtonsView: SeekBarWithIconButtonsView = + fontScalingDialog.findViewById(R.id.font_scaling_slider)!! + val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!! + + seekBarWithIconButtonsView.setProgress(0) + + iconEnd.performClick() + + val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f) + assertThat(seekBar.getProgress()).isEqualTo(1) + assertThat(currentScale).isEqualTo(fontSizeValueArray[1].toFloat()) + + fontScalingDialog.dismiss() + } + + @Test + fun progressIsMax_clickIconStart_seekBarProgressDecreaseOne_fontSizeScaled() { + fontScalingDialog.show() + + val iconStart: ImageView = fontScalingDialog.findViewById(R.id.icon_start)!! + val seekBarWithIconButtonsView: SeekBarWithIconButtonsView = + fontScalingDialog.findViewById(R.id.font_scaling_slider)!! + val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!! + + seekBarWithIconButtonsView.setProgress(fontSizeValueArray.size - 1) + + iconStart.performClick() + + val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f) + assertThat(seekBar.getProgress()).isEqualTo(fontSizeValueArray.size - 2) + assertThat(currentScale) + .isEqualTo(fontSizeValueArray[fontSizeValueArray.size - 2].toFloat()) + + fontScalingDialog.dismiss() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt index ed0cd7ed9b24..31d0d1292fe7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.animation import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.graphics.Typeface +import android.graphics.fonts.FontVariationAxis import android.testing.AndroidTestingRunner import android.text.Layout import android.text.StaticLayout @@ -178,4 +179,71 @@ class TextAnimatorTest : SysuiTestCase() { assertThat(paint.typeface).isSameInstanceAs(prevTypeface) } + + @Test + fun testSetTextStyle_addWeight() { + testWeightChange("", 100, FontVariationAxis.fromFontVariationSettings("'wght' 100")!!) + } + + @Test + fun testSetTextStyle_changeWeight() { + testWeightChange( + "'wght' 500", + 100, + FontVariationAxis.fromFontVariationSettings("'wght' 100")!! + ) + } + + @Test + fun testSetTextStyle_addWeightWithOtherAxis() { + testWeightChange( + "'wdth' 100", + 100, + FontVariationAxis.fromFontVariationSettings("'wght' 100, 'wdth' 100")!! + ) + } + + @Test + fun testSetTextStyle_changeWeightWithOtherAxis() { + testWeightChange( + "'wght' 500, 'wdth' 100", + 100, + FontVariationAxis.fromFontVariationSettings("'wght' 100, 'wdth' 100")!! + ) + } + + private fun testWeightChange( + initialFontVariationSettings: String, + weight: Int, + expectedFontVariationSettings: Array<FontVariationAxis> + ) { + val layout = makeLayout("Hello, World", PAINT) + val valueAnimator = mock(ValueAnimator::class.java) + val textInterpolator = mock(TextInterpolator::class.java) + val paint = + TextPaint().apply { + typeface = Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf") + fontVariationSettings = initialFontVariationSettings + } + `when`(textInterpolator.targetPaint).thenReturn(paint) + + val textAnimator = + TextAnimator(layout, {}).apply { + this.textInterpolator = textInterpolator + this.animator = valueAnimator + } + textAnimator.setTextStyle(weight = weight, animate = false) + + val resultFontVariationList = + FontVariationAxis.fromFontVariationSettings( + textInterpolator.targetPaint.fontVariationSettings + ) + expectedFontVariationSettings.forEach { expectedAxis -> + val resultAxis = resultFontVariationList?.filter { it.tag == expectedAxis.tag }?.get(0) + assertThat(resultAxis).isNotNull() + if (resultAxis != null) { + assertThat(resultAxis.styleValue).isEqualTo(expectedAxis.styleValue) + } + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java new file mode 100644 index 000000000000..2ed03465c6f0 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsViewTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.common.ui.view; + +import static com.google.common.truth.Truth.assertThat; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.widget.ImageView; +import android.widget.SeekBar; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link SeekBarWithIconButtonsView} + */ +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class SeekBarWithIconButtonsViewTest extends SysuiTestCase { + + private ImageView mIconStart; + private ImageView mIconEnd; + private SeekBar mSeekbar; + private SeekBarWithIconButtonsView mIconDiscreteSliderLinearLayout; + + @Before + public void setUp() { + mIconDiscreteSliderLinearLayout = new SeekBarWithIconButtonsView(mContext); + mIconStart = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_start); + mIconEnd = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_end); + mSeekbar = mIconDiscreteSliderLinearLayout.findViewById(R.id.seekbar); + } + + @Test + public void setSeekBarProgressZero_startIconAndFrameDisabled() { + mIconDiscreteSliderLinearLayout.setProgress(0); + + assertThat(mIconStart.isEnabled()).isFalse(); + assertThat(mIconEnd.isEnabled()).isTrue(); + } + + @Test + public void setSeekBarProgressMax_endIconAndFrameDisabled() { + mIconDiscreteSliderLinearLayout.setProgress(mSeekbar.getMax()); + + assertThat(mIconEnd.isEnabled()).isFalse(); + assertThat(mIconStart.isEnabled()).isTrue(); + } + + @Test + public void setSeekBarProgressMax_allIconsAndFramesEnabled() { + // We are using the default value for the max of seekbar. + // Therefore, the max value will be DEFAULT_SEEKBAR_MAX = 6. + mIconDiscreteSliderLinearLayout.setProgress(1); + + assertThat(mIconStart.isEnabled()).isTrue(); + assertThat(mIconEnd.isEnabled()).isTrue(); + } + + @Test + public void clickIconEnd_currentProgressIsOneToMax_reachesMax() { + mIconDiscreteSliderLinearLayout.setProgress(mSeekbar.getMax() - 1); + mIconEnd.performClick(); + + assertThat(mSeekbar.getProgress()).isEqualTo(mSeekbar.getMax()); + } + + @Test + public void clickIconStart_currentProgressIsOne_reachesZero() { + mIconDiscreteSliderLinearLayout.setProgress(1); + mIconStart.performClick(); + + assertThat(mSeekbar.getProgress()).isEqualTo(0); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java index 9f4a7c820efc..b3329eb5f5b2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java @@ -32,7 +32,9 @@ import androidx.test.filters.SmallTest; import com.android.settingslib.dream.DreamBackend; import com.android.systemui.SysuiTestCase; +import com.android.systemui.condition.SelfExecutingMonitor; import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.shared.condition.Monitor; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.time.FakeSystemClock; @@ -66,13 +68,16 @@ public class ComplicationTypesUpdaterTest extends SysuiTestCase { private ComplicationTypesUpdater mController; + private Monitor mMonitor; + @Before public void setUp() { MockitoAnnotations.initMocks(this); when(mDreamBackend.getEnabledComplications()).thenReturn(new HashSet<>()); + mMonitor = SelfExecutingMonitor.createInstance(); mController = new ComplicationTypesUpdater(mDreamBackend, mExecutor, - mSecureSettings, mDreamOverlayStateController); + mSecureSettings, mDreamOverlayStateController, mMonitor); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java index ec448f94ba83..f6662d05c817 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java @@ -29,7 +29,9 @@ import android.view.View; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.condition.SelfExecutingMonitor; import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.shared.condition.Monitor; import org.junit.Before; import org.junit.Test; @@ -69,10 +71,13 @@ public class DreamClockTimeComplicationTest extends SysuiTestCase { @Mock private ComplicationLayoutParams mLayoutParams; + private Monitor mMonitor; + @Before public void setup() { MockitoAnnotations.initMocks(this); when(mDreamClockTimeViewHolderProvider.get()).thenReturn(mDreamClockTimeViewHolder); + mMonitor = SelfExecutingMonitor.createInstance(); } /** @@ -83,7 +88,8 @@ public class DreamClockTimeComplicationTest extends SysuiTestCase { final DreamClockTimeComplication.Registrant registrant = new DreamClockTimeComplication.Registrant( mDreamOverlayStateController, - mComplication); + mComplication, + mMonitor); registrant.start(); verify(mDreamOverlayStateController).addComplication(eq(mComplication)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java index a4cf15c3fafa..3312c4335ab4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java @@ -37,7 +37,8 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.common.ui.view.LaunchableImageView; +import com.android.systemui.animation.view.LaunchableImageView; +import com.android.systemui.condition.SelfExecutingMonitor; import com.android.systemui.controls.ControlsServiceInfo; import com.android.systemui.controls.controller.ControlsController; import com.android.systemui.controls.controller.StructureInfo; @@ -46,6 +47,7 @@ import com.android.systemui.controls.management.ControlsListingController; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.shared.condition.Monitor; import org.junit.Before; import org.junit.Test; @@ -101,6 +103,8 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { @Captor private ArgumentCaptor<DreamOverlayStateController.Callback> mStateCallbackCaptor; + private Monitor mMonitor; + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -112,6 +116,8 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { Optional.of(mControlsListingController)); when(mControlsComponent.getVisibility()).thenReturn(AVAILABLE); when(mView.findViewById(R.id.home_controls_chip)).thenReturn(mHomeControlsView); + + mMonitor = SelfExecutingMonitor.createInstance(); } @Test @@ -126,7 +132,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceNotAvailable_noFavorites_doNotAddComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setHaveFavorites(false); @@ -139,7 +145,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceAvailable_noFavorites_doNotAddComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setHaveFavorites(false); @@ -152,7 +158,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceAvailable_noFavorites_panel_addComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setHaveFavorites(false); @@ -165,7 +171,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceNotAvailable_haveFavorites_doNotAddComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setHaveFavorites(true); @@ -178,7 +184,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceAvailable_haveFavorites_addComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setHaveFavorites(true); @@ -191,7 +197,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_checkAvailabilityWhenDreamOverlayBecomesActive() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setServiceAvailable(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java index c8b2b2556828..ef62abfe36de 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java @@ -30,9 +30,12 @@ import android.view.View; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.condition.SelfExecutingMonitor; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.smartspace.DreamSmartspaceController; import com.android.systemui.plugins.BcSmartspaceDataPlugin; +import com.android.systemui.shared.condition.Condition; +import com.android.systemui.shared.condition.Monitor; import org.junit.Before; import org.junit.Test; @@ -43,6 +46,8 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.Collections; +import java.util.HashSet; +import java.util.Set; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -60,9 +65,14 @@ public class SmartSpaceComplicationTest extends SysuiTestCase { @Mock private View mBcSmartspaceView; + private Monitor mMonitor; + + private final Set<Condition> mPreconditions = new HashSet<>(); + @Before public void setup() { MockitoAnnotations.initMocks(this); + mMonitor = SelfExecutingMonitor.createInstance(); } /** @@ -79,7 +89,8 @@ public class SmartSpaceComplicationTest extends SysuiTestCase { return new SmartSpaceComplication.Registrant( mDreamOverlayStateController, mComplication, - mSmartspaceController); + mSmartspaceController, + mMonitor); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugRestarterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugRestarterTest.kt index ed167212c96a..686782f59355 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugRestarterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugRestarterTest.kt @@ -20,6 +20,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE +import com.android.systemui.util.mockito.any import org.junit.Before import org.junit.Test import org.mockito.ArgumentCaptor @@ -48,22 +49,22 @@ class FeatureFlagsDebugRestarterTest : SysuiTestCase() { @Test fun testRestart_ImmediateWhenAsleep() { whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP) - restarter.restartSystemUI() - verify(systemExitRestarter).restartSystemUI() + restarter.restartSystemUI("Restart for test") + verify(systemExitRestarter).restartSystemUI(any()) } @Test fun testRestart_WaitsForSceenOff() { whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_AWAKE) - restarter.restartSystemUI() - verify(systemExitRestarter, never()).restartSystemUI() + restarter.restartSystemUI("Restart for test") + verify(systemExitRestarter, never()).restartSystemUI(any()) val captor = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer::class.java) verify(wakefulnessLifecycle).addObserver(captor.capture()) captor.value.onFinishedGoingToSleep() - verify(systemExitRestarter).restartSystemUI() + verify(systemExitRestarter).restartSystemUI(any()) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt index d8bbd04bfd4a..2bcd75b7c707 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt @@ -28,7 +28,6 @@ import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.withArgCaptor import com.android.systemui.util.settings.GlobalSettings -import com.android.systemui.util.settings.SecureSettings import com.google.common.truth.Truth.assertThat import org.junit.Assert import org.junit.Before @@ -63,8 +62,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Mock private lateinit var globalSettings: GlobalSettings @Mock - private lateinit var secureSettings: SecureSettings - @Mock private lateinit var systemProperties: SystemPropertiesHelper @Mock private lateinit var resources: Resources @@ -92,7 +89,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() { flagManager, mockContext, globalSettings, - secureSettings, systemProperties, resources, serverFlagReader, diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseRestarterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseRestarterTest.kt index 7d807e2ff207..6060afe495f5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseRestarterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseRestarterTest.kt @@ -22,6 +22,7 @@ import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -63,7 +64,7 @@ class FeatureFlagsReleaseRestarterTest : SysuiTestCase() { whenever(batteryController.isPluggedIn).thenReturn(true) assertThat(executor.numPending()).isEqualTo(0) - restarter.restartSystemUI() + restarter.restartSystemUI("Restart for test") assertThat(executor.numPending()).isEqualTo(1) } @@ -72,11 +73,11 @@ class FeatureFlagsReleaseRestarterTest : SysuiTestCase() { whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP) whenever(batteryController.isPluggedIn).thenReturn(true) - restarter.restartSystemUI() - verify(systemExitRestarter, never()).restartSystemUI() + restarter.restartSystemUI("Restart for test") + verify(systemExitRestarter, never()).restartSystemUI("Restart for test") executor.advanceClockToLast() executor.runAllReady() - verify(systemExitRestarter).restartSystemUI() + verify(systemExitRestarter).restartSystemUI(any()) } @Test @@ -85,7 +86,7 @@ class FeatureFlagsReleaseRestarterTest : SysuiTestCase() { whenever(batteryController.isPluggedIn).thenReturn(true) assertThat(executor.numPending()).isEqualTo(0) - restarter.restartSystemUI() + restarter.restartSystemUI("Restart for test") assertThat(executor.numPending()).isEqualTo(0) } @@ -95,7 +96,7 @@ class FeatureFlagsReleaseRestarterTest : SysuiTestCase() { whenever(batteryController.isPluggedIn).thenReturn(false) assertThat(executor.numPending()).isEqualTo(0) - restarter.restartSystemUI() + restarter.restartSystemUI("Restart for test") assertThat(executor.numPending()).isEqualTo(0) } @@ -105,8 +106,8 @@ class FeatureFlagsReleaseRestarterTest : SysuiTestCase() { whenever(batteryController.isPluggedIn).thenReturn(true) assertThat(executor.numPending()).isEqualTo(0) - restarter.restartSystemUI() - restarter.restartSystemUI() + restarter.restartSystemUI("Restart for test") + restarter.restartSystemUI("Restart for test") assertThat(executor.numPending()).isEqualTo(1) } @@ -115,7 +116,7 @@ class FeatureFlagsReleaseRestarterTest : SysuiTestCase() { whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_AWAKE) whenever(batteryController.isPluggedIn).thenReturn(true) assertThat(executor.numPending()).isEqualTo(0) - restarter.restartSystemUI() + restarter.restartSystemUI("Restart for test") val captor = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer::class.java) verify(wakefulnessLifecycle).addObserver(captor.capture()) @@ -131,7 +132,7 @@ class FeatureFlagsReleaseRestarterTest : SysuiTestCase() { whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP) whenever(batteryController.isPluggedIn).thenReturn(false) assertThat(executor.numPending()).isEqualTo(0) - restarter.restartSystemUI() + restarter.restartSystemUI("Restart for test") val captor = ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback::class.java) diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt index 1633912abec7..4ebf9741ce22 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt @@ -45,7 +45,7 @@ class ServerFlagReaderImplTest : SysuiTestCase() { fun setup() { MockitoAnnotations.initMocks(this) - serverFlagReader = ServerFlagReaderImpl(NAMESPACE, deviceConfig, executor) + serverFlagReader = ServerFlagReaderImpl(NAMESPACE, deviceConfig, executor, false) } @Test @@ -56,6 +56,6 @@ class ServerFlagReaderImplTest : SysuiTestCase() { deviceConfig.setProperty(NAMESPACE, "flag_override_1", "1", false) executor.runAllReady() - verify(changeListener).onChange() + verify(changeListener).onChange(flag) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt index 58cdec447cc6..5bb8367432fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt @@ -18,47 +18,58 @@ package com.android.systemui.keyguard.data.quickaffordance import android.app.StatusBarManager +import android.app.admin.DevicePolicyManager import android.content.Context import android.content.pm.PackageManager +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.camera.CameraGestureHelper +import com.android.systemui.settings.UserTracker import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class CameraQuickAffordanceConfigTest : SysuiTestCase() { @Mock private lateinit var cameraGestureHelper: CameraGestureHelper @Mock private lateinit var context: Context @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var userTracker: UserTracker + @Mock private lateinit var devicePolicyManager: DevicePolicyManager private lateinit var underTest: CameraQuickAffordanceConfig + private lateinit var testScope: TestScope @Before fun setUp() { MockitoAnnotations.initMocks(this) - setLaunchable(true) + setLaunchable() + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) underTest = CameraQuickAffordanceConfig( context, packageManager, - ) { - cameraGestureHelper - } + { cameraGestureHelper }, + userTracker, + devicePolicyManager, + testDispatcher, + ) } @Test @@ -73,23 +84,57 @@ class CameraQuickAffordanceConfigTest : SysuiTestCase() { } @Test - fun `getPickerScreenState - default when launchable`() = runTest { - setLaunchable(true) + fun `getPickerScreenState - default when launchable`() = + testScope.runTest { + setLaunchable(true) - Truth.assertThat(underTest.getPickerScreenState()) - .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java) - } + Truth.assertThat(underTest.getPickerScreenState()) + .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java) + } @Test - fun `getPickerScreenState - unavailable when not launchable`() = runTest { - setLaunchable(false) + fun `getPickerScreenState - unavailable when camera app not installed`() = + testScope.runTest { + setLaunchable(isCameraAppInstalled = false) - Truth.assertThat(underTest.getPickerScreenState()) - .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) - } + Truth.assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) + } + + @Test + fun `getPickerScreenState - unavailable when camera disabled by admin`() = + testScope.runTest { + setLaunchable(isCameraDisabledByDeviceAdmin = true) + + Truth.assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) + } + + @Test + fun `getPickerScreenState - unavailable when secure camera disabled by admin`() = + testScope.runTest { + setLaunchable(isSecureCameraDisabledByDeviceAdmin = true) + + Truth.assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) + } - private fun setLaunchable(isLaunchable: Boolean) { + private fun setLaunchable( + isCameraAppInstalled: Boolean = true, + isCameraDisabledByDeviceAdmin: Boolean = false, + isSecureCameraDisabledByDeviceAdmin: Boolean = false, + ) { whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) - .thenReturn(isLaunchable) + .thenReturn(isCameraAppInstalled) + whenever(devicePolicyManager.getCameraDisabled(null, userTracker.userId)) + .thenReturn(isCameraDisabledByDeviceAdmin) + whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId)) + .thenReturn( + if (isSecureCameraDisabledByDeviceAdmin) { + DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA + } else { + 0 + } + ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt index 15b85ded5fd1..64839e2c1105 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfigTest.kt @@ -22,6 +22,7 @@ import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS import android.provider.Settings.Global.ZEN_MODE_OFF import android.provider.Settings.Secure.ZEN_DURATION_FOREVER import android.provider.Settings.Secure.ZEN_DURATION_PROMPT +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.settingslib.notification.EnableZenModeDialog import com.android.systemui.R @@ -51,7 +52,6 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock @@ -60,7 +60,7 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class DoNotDisturbQuickAffordanceConfigTest : SysuiTestCase() { @Mock private lateinit var zenModeController: ZenModeController diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt index 9fa7db127e1f..31391ee8c0eb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.Context +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.common.shared.model.Icon @@ -35,13 +36,12 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() { @Mock private lateinit var context: Context diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt index 659c1e573ca3..2c1c04cefdc7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.data.quickaffordance +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase @@ -34,13 +35,12 @@ import kotlinx.coroutines.test.runBlockingTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class HomeControlsKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Mock private lateinit var component: ControlsComponent diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt index 3b0169d77063..3bae7f709b69 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt @@ -20,6 +20,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.Context import android.content.res.Resources import android.provider.Settings +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase @@ -40,7 +41,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock @@ -48,7 +48,7 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class KeyguardQuickAffordanceLegacySettingSyncerTest : SysuiTestCase() { @Mock private lateinit var sharedPrefs: FakeSharedPreferences diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt index 3d6571349a3e..1259b478dec5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt @@ -20,6 +20,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.Intent import android.content.SharedPreferences import android.content.pm.UserInfo +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase @@ -40,7 +41,6 @@ import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock @@ -51,7 +51,7 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { @Mock private lateinit var userFileManager: UserFileManager diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt index b21cec970136..c08ef42eef03 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.pm.UserInfo import android.os.UserHandle +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.settings.FakeUserTracker @@ -37,13 +38,12 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() { @Mock private lateinit var userHandle: UserHandle diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt index 34f3ed804bfa..facc7475f034 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt @@ -21,6 +21,7 @@ import android.content.Context import android.media.AudioManager import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Observer +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FeatureFlags @@ -47,7 +48,6 @@ import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.Mockito.verifyZeroInteractions @@ -55,8 +55,8 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) -class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() { +@RunWith(AndroidJUnit4::class) +class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() { @Mock private lateinit var featureFlags: FeatureFlags diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt index 9d2ddffddb5d..1adf808cf645 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.Intent +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult @@ -33,13 +34,12 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Mock private lateinit var controller: QRCodeScannerController diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt index 8f56b9560ec3..752963fad92d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt @@ -20,6 +20,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.graphics.drawable.Drawable import android.service.quickaccesswallet.GetWalletCardsResponse import android.service.quickaccesswallet.QuickAccessWalletClient +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase @@ -41,14 +42,13 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { @Mock private lateinit var walletController: QuickAccessWalletController diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt index 805dcec0f5b1..f1b9c5f0fff8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfigTest.kt @@ -17,22 +17,26 @@ package com.android.systemui.keyguard.data.quickaffordance +import android.app.admin.DevicePolicyManager +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.ActivityIntentHelper import com.android.systemui.SysuiTestCase import com.android.systemui.camera.CameraIntentsWrapper import com.android.systemui.coroutines.collectLastValue import com.android.systemui.settings.FakeUserTracker +import com.android.systemui.settings.UserTracker import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock @@ -40,63 +44,98 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() { @Mock private lateinit var activityIntentHelper: ActivityIntentHelper + @Mock private lateinit var devicePolicyManager: DevicePolicyManager private lateinit var underTest: VideoCameraQuickAffordanceConfig + private lateinit var userTracker: UserTracker + private lateinit var testScope: TestScope @Before fun setUp() { MockitoAnnotations.initMocks(this) + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) + userTracker = FakeUserTracker() underTest = VideoCameraQuickAffordanceConfig( context = context, cameraIntents = CameraIntentsWrapper(context), activityIntentHelper = activityIntentHelper, - userTracker = FakeUserTracker(), + userTracker = userTracker, + devicePolicyManager = devicePolicyManager, + backgroundDispatcher = testDispatcher, ) } @Test - fun `lockScreenState - visible when launchable`() = runTest { - setLaunchable(true) + fun `lockScreenState - visible when launchable`() = + testScope.runTest { + setLaunchable() - val lockScreenState = collectLastValue(underTest.lockScreenState) + val lockScreenState = collectLastValue(underTest.lockScreenState) - assertThat(lockScreenState()) - .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java) - } + assertThat(lockScreenState()) + .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java) + } @Test - fun `lockScreenState - hidden when not launchable`() = runTest { - setLaunchable(false) + fun `lockScreenState - hidden when app not installed on device`() = + testScope.runTest { + setLaunchable(isVideoCameraAppInstalled = false) - val lockScreenState = collectLastValue(underTest.lockScreenState) + val lockScreenState = collectLastValue(underTest.lockScreenState) - assertThat(lockScreenState()) - .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) - } + assertThat(lockScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) + } @Test - fun `getPickerScreenState - default when launchable`() = runTest { - setLaunchable(true) + fun `lockScreenState - hidden when camera disabled by admin`() = + testScope.runTest { + setLaunchable(isCameraDisabledByAdmin = true) - assertThat(underTest.getPickerScreenState()) - .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java) - } + val lockScreenState = collectLastValue(underTest.lockScreenState) + + assertThat(lockScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) + } @Test - fun `getPickerScreenState - unavailable when not launchable`() = runTest { - setLaunchable(false) + fun `getPickerScreenState - default when launchable`() = + testScope.runTest { + setLaunchable() - assertThat(underTest.getPickerScreenState()) - .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) - } + assertThat(underTest.getPickerScreenState()) + .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java) + } - private fun setLaunchable(isLaunchable: Boolean) { + @Test + fun `getPickerScreenState - unavailable when app not installed on device`() = + testScope.runTest { + setLaunchable(isVideoCameraAppInstalled = false) + + assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) + } + + @Test + fun `getPickerScreenState - unavailable when camera disabled by admin`() = + testScope.runTest { + setLaunchable(isCameraDisabledByAdmin = true) + + assertThat(underTest.getPickerScreenState()) + .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice) + } + + private fun setLaunchable( + isVideoCameraAppInstalled: Boolean = true, + isCameraDisabledByAdmin: Boolean = false, + ) { whenever( activityIntentHelper.getTargetActivityInfo( any(), @@ -105,11 +144,13 @@ class VideoCameraQuickAffordanceConfigTest : SysuiTestCase() { ) ) .thenReturn( - if (isLaunchable) { + if (isVideoCameraAppInstalled) { mock() } else { null } ) + whenever(devicePolicyManager.getCameraDisabled(null, userTracker.userId)) + .thenReturn(isCameraDisabledByAdmin) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt index 444a2a7eada6..ff22f1e0a52a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.data.repository +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.ViewMediatorCallback import com.android.systemui.SysuiTestCase @@ -26,13 +27,12 @@ import kotlinx.coroutines.test.TestCoroutineScope import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class KeyguardBouncerRepositoryTest : SysuiTestCase() { @Mock private lateinit var systemClock: SystemClock diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt index 6099f011a90d..86e8c9accc45 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt @@ -19,9 +19,11 @@ package com.android.systemui.keyguard.data.repository import android.content.pm.UserInfo import android.os.UserHandle +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceProviderClientFactory import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig @@ -39,23 +41,19 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.CoroutineScope -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 kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { private lateinit var underTest: KeyguardQuickAffordanceRepository @@ -65,12 +63,14 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { private lateinit var userTracker: FakeUserTracker private lateinit var client1: FakeCustomizationProviderClient private lateinit var client2: FakeCustomizationProviderClient + private lateinit var testScope: TestScope @Before fun setUp() { config1 = FakeKeyguardQuickAffordanceConfig(FakeCustomizationProviderClient.AFFORDANCE_1) config2 = FakeKeyguardQuickAffordanceConfig(FakeCustomizationProviderClient.AFFORDANCE_2) - val scope = CoroutineScope(IMMEDIATE) + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) userTracker = FakeUserTracker() val localUserSelectionManager = KeyguardQuickAffordanceLocalUserSelectionManager( @@ -93,7 +93,7 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { client2 = FakeCustomizationProviderClient() val remoteUserSelectionManager = KeyguardQuickAffordanceRemoteUserSelectionManager( - scope = scope, + scope = testScope.backgroundScope, userTracker = userTracker, clientFactory = FakeKeyguardQuickAffordanceProviderClientFactory( @@ -116,14 +116,14 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { underTest = KeyguardQuickAffordanceRepository( appContext = context, - scope = scope, + scope = testScope.backgroundScope, localUserSelectionManager = localUserSelectionManager, remoteUserSelectionManager = remoteUserSelectionManager, userTracker = userTracker, legacySettingSyncer = KeyguardQuickAffordanceLegacySettingSyncer( - scope = scope, - backgroundDispatcher = IMMEDIATE, + scope = testScope.backgroundScope, + backgroundDispatcher = testDispatcher, secureSettings = FakeSettings(), selectionsManager = localUserSelectionManager, ), @@ -135,15 +135,14 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { @Test fun setSelections() = - runBlocking(IMMEDIATE) { - var configsBySlotId: Map<String, List<KeyguardQuickAffordanceConfig>>? = null - val job = underTest.selections.onEach { configsBySlotId = it }.launchIn(this) + testScope.runTest { + val configsBySlotId = collectLastValue(underTest.selections) val slotId1 = "slot1" val slotId2 = "slot2" underTest.setSelections(slotId1, listOf(config1.key)) assertSelections( - configsBySlotId, + configsBySlotId(), mapOf( slotId1 to listOf(config1), ), @@ -151,7 +150,7 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { underTest.setSelections(slotId2, listOf(config2.key)) assertSelections( - configsBySlotId, + configsBySlotId(), mapOf( slotId1 to listOf(config1), slotId2 to listOf(config2), @@ -161,19 +160,17 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { underTest.setSelections(slotId1, emptyList()) underTest.setSelections(slotId2, listOf(config1.key)) assertSelections( - configsBySlotId, + configsBySlotId(), mapOf( slotId1 to emptyList(), slotId2 to listOf(config1), ), ) - - job.cancel() } @Test fun getAffordancePickerRepresentations() = - runBlocking(IMMEDIATE) { + testScope.runTest { assertThat(underTest.getAffordancePickerRepresentations()) .isEqualTo( listOf( @@ -226,7 +223,7 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { @Test fun `selections for secondary user`() = - runBlocking(IMMEDIATE) { + testScope.runTest { userTracker.set( userInfos = listOf( @@ -252,12 +249,10 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, affordanceId = FakeCustomizationProviderClient.AFFORDANCE_2, ) - val observed = mutableListOf<Map<String, List<KeyguardQuickAffordanceConfig>>>() - val job = underTest.selections.onEach { observed.add(it) }.launchIn(this) - yield() + val observed = collectLastValue(underTest.selections) assertSelections( - observed = observed.last(), + observed = observed(), expected = mapOf( KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to @@ -266,8 +261,6 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { ), ) ) - - job.cancel() } private fun assertSelections( @@ -283,7 +276,6 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { } companion object { - private val IMMEDIATE = Dispatchers.Main.immediate private const val SECONDARY_USER_1 = UserHandle.MIN_SECONDARY_USER_ID + 1 private const val SECONDARY_USER_2 = UserHandle.MIN_SECONDARY_USER_ID + 2 } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt index f997d18a57a5..8bb6a85ff34b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.repository import android.graphics.Point import android.hardware.biometrics.BiometricSourceType +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback @@ -54,13 +55,12 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class KeyguardRepositoryImplTest : SysuiTestCase() { @Mock private lateinit var statusBarStateController: StatusBarStateController diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt index 32cec09c3580..ae227b4b8370 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt @@ -20,6 +20,7 @@ import android.animation.ValueAnimator import android.util.Log import android.util.Log.TerribleFailure import android.util.Log.TerribleFailureHandler +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.animation.Interpolators @@ -43,10 +44,9 @@ import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class KeyguardTransitionRepositoryTest : SysuiTestCase() { private lateinit var underTest: KeyguardTransitionRepository diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt index 4b069051423c..a1811371adb9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.repository import android.app.trust.TrustManager import android.content.pm.UserInfo +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.logging.TrustRepositoryLogger import com.android.systemui.SysuiTestCase @@ -33,7 +34,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock @@ -43,7 +43,7 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class TrustRepositoryTest : SysuiTestCase() { @Mock private lateinit var trustManager: TrustManager @Captor private lateinit var listenerCaptor: ArgumentCaptor<TrustManager.TrustListener> diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt index 8caf60fb3ebd..7ded354c92cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.domain.interactor +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.ViewMediatorCallback @@ -36,14 +37,13 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class AlternateBouncerInteractorTest : SysuiTestCase() { private lateinit var underTest: AlternateBouncerInteractor private lateinit var bouncerRepository: KeyguardBouncerRepository diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt index d9382434985f..7d4861bdcb98 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.domain.interactor import android.app.StatusBarManager import android.content.Context +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue @@ -36,12 +37,12 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mockito.mock +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class KeyguardInteractorTest : SysuiTestCase() { private lateinit var commandQueue: FakeCommandQueue private lateinit var featureFlags: FakeFeatureFlags diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt index 9d60b16eba8b..51988ef1ab78 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.domain.interactor import android.content.Intent +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase @@ -39,7 +40,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.Mock import org.mockito.Mockito.never @@ -48,7 +48,7 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class KeyguardLongPressInteractorTest : SysuiTestCase() { @Mock private lateinit var activityStarter: ActivityStarter diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt index 8cff0ae84181..ec708578a990 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.domain.interactor import android.os.UserHandle +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils import com.android.systemui.R @@ -60,7 +61,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock @@ -68,7 +68,7 @@ import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { @Mock private lateinit var lockPatternUtils: LockPatternUtils diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt index 6333b244fd38..3d13d8092651 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.domain.interactor +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -29,17 +30,17 @@ import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING import com.android.systemui.keyguard.shared.model.TransitionState.STARTED import com.android.systemui.keyguard.shared.model.TransitionStep import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) +@kotlinx.coroutines.ExperimentalCoroutinesApi class KeyguardTransitionInteractorTest : SysuiTestCase() { private lateinit var underTest: KeyguardTransitionInteractor @@ -53,7 +54,7 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { @Test fun `transition collectors receives only appropriate events`() = - runBlocking(IMMEDIATE) { + runTest(UnconfinedTestDispatcher()) { var lockscreenToAodSteps = mutableListOf<TransitionStep>() val job1 = underTest.lockscreenToAodTransition @@ -87,10 +88,9 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { @Test fun dozeAmountTransitionTest() = - runBlocking(IMMEDIATE) { + runTest(UnconfinedTestDispatcher()) { var dozeAmountSteps = mutableListOf<TransitionStep>() - val job = - underTest.dozeAmountTransition.onEach { dozeAmountSteps.add(it) }.launchIn(this) + val job = underTest.dozeAmountTransition.onEach { dozeAmountSteps.add(it) }.launchIn(this) val steps = mutableListOf<TransitionStep>() @@ -119,10 +119,9 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { @Test fun keyguardStateTests() = - runBlocking(IMMEDIATE) { + runTest(UnconfinedTestDispatcher()) { var finishedSteps = mutableListOf<KeyguardState>() - val job = - underTest.finishedKeyguardState.onEach { finishedSteps.add(it) }.launchIn(this) + val job = underTest.finishedKeyguardState.onEach { finishedSteps.add(it) }.launchIn(this) val steps = mutableListOf<TransitionStep>() @@ -143,12 +142,10 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { @Test fun finishedKeyguardTransitionStepTests() = - runBlocking(IMMEDIATE) { + runTest(UnconfinedTestDispatcher()) { var finishedSteps = mutableListOf<TransitionStep>() val job = - underTest.finishedKeyguardTransitionStep - .onEach { finishedSteps.add(it) } - .launchIn(this) + underTest.finishedKeyguardTransitionStep.onEach { finishedSteps.add(it) }.launchIn(this) val steps = mutableListOf<TransitionStep>() @@ -169,12 +166,10 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { @Test fun startedKeyguardTransitionStepTests() = - runBlocking(IMMEDIATE) { + runTest(UnconfinedTestDispatcher()) { var startedSteps = mutableListOf<TransitionStep>() val job = - underTest.startedKeyguardTransitionStep - .onEach { startedSteps.add(it) } - .launchIn(this) + underTest.startedKeyguardTransitionStep.onEach { startedSteps.add(it) }.launchIn(this) val steps = mutableListOf<TransitionStep>() @@ -192,8 +187,4 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { job.cancel() } - - companion object { - private val IMMEDIATE = Dispatchers.Main.immediate - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt index 31662145dfbe..62366164a17d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.domain.interactor +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -33,11 +34,10 @@ import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.MockitoAnnotations @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class LightRevealScrimInteractorTest : SysuiTestCase() { private val fakeKeyguardTransitionRepository = FakeKeyguardTransitionRepository() private val fakeLightRevealScrimRepository = FakeLightRevealScrimRepository() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt index fbfeca9c2a25..f86ac795427c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt @@ -17,18 +17,18 @@ package com.android.systemui.keyguard.domain.interactor import android.view.View +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class PrimaryBouncerCallbackInteractorTest : SysuiTestCase() { private val mPrimaryBouncerCallbackInteractor = PrimaryBouncerCallbackInteractor() @Mock diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt index ea7bc91cd2d5..75b74b0cfe28 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.domain.interactor import android.os.Looper +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardUpdateMonitor @@ -35,12 +36,11 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.MockitoAnnotations @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class PrimaryBouncerInteractorWithCoroutinesTest : SysuiTestCase() { private lateinit var repository: FakeKeyguardBouncerRepository @Mock private lateinit var bouncerView: BouncerView diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt index 06e397d8fb8f..706154e2b90a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -33,10 +34,9 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() { private lateinit var underTest: DreamingToLockscreenTransitionViewModel private lateinit var repository: FakeKeyguardTransitionRepository diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt index 14c3b504d0ae..b15ce1091646 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -32,10 +33,9 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class GoneToDreamingTransitionViewModelTest : SysuiTestCase() { private lateinit var underTest: GoneToDreamingTransitionViewModel private lateinit var repository: FakeKeyguardTransitionRepository diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt index 37271346a51f..586af626d29e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt @@ -16,28 +16,29 @@ package com.android.systemui.keyguard.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.data.BouncerView import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) +@kotlinx.coroutines.ExperimentalCoroutinesApi class KeyguardBouncerViewModelTest : SysuiTestCase() { lateinit var underTest: KeyguardBouncerViewModel @Mock lateinit var bouncerView: BouncerView @@ -51,7 +52,7 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() { @Test fun setMessage() = - runBlocking(Dispatchers.Main.immediate) { + runTest { val flow = MutableStateFlow<BouncerShowMessageModel?>(null) var message: BouncerShowMessageModel? = null Mockito.`when`(bouncerInteractor.showMessage) @@ -62,6 +63,8 @@ class KeyguardBouncerViewModelTest : SysuiTestCase() { flow.value = BouncerShowMessageModel(message = "abc", colorStateList = null) val job = underTest.bouncerShowMessage.onEach { message = it }.launchIn(this) + // Run the tasks that are pending at this point of virtual time. + runCurrent() assertThat(message?.message).isEqualTo("abc") job.cancel() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt index ed31dc39dd90..d94c1089ccb7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -32,10 +33,9 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() { private lateinit var underTest: LockscreenToDreamingTransitionViewModel private lateinit var repository: FakeKeyguardTransitionRepository diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt index 458b31519500..12ec24de502b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -32,10 +33,9 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() { private lateinit var underTest: LockscreenToOccludedTransitionViewModel private lateinit var repository: FakeKeyguardTransitionRepository diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt index a36214ecdb2f..0c4e84521a36 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -32,10 +33,9 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class) class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() { private lateinit var underTest: OccludedToLockscreenTransitionViewModel private lateinit var repository: FakeKeyguardTransitionRepository diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt index 6f1b42bf1d19..a07a714ebc77 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt @@ -827,6 +827,24 @@ class MediaDataManagerTest : SysuiTestCase() { } @Test + fun testAddResumptionControls_hasNoExtras() { + whenever(mediaFlags.isResumeProgressEnabled()).thenReturn(true) + + // WHEN resumption controls are added that do not have any extras + val desc = + MediaDescription.Builder().run { + setTitle(SESSION_TITLE) + build() + } + addResumeControlAndLoad(desc) + + // Resume progress is null + val data = mediaDataCaptor.value + assertThat(data.resumption).isTrue() + assertThat(data.resumeProgress).isEqualTo(null) + } + + @Test fun testResumptionDisabled_dismissesResumeControls() { // WHEN there are resume controls and resumption is switched off val desc = @@ -1879,6 +1897,20 @@ class MediaDataManagerTest : SysuiTestCase() { .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean()) } + @Test + fun testSessionDestroyed_noNotificationKey_stillRemoved() { + whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(true) + whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true) + + // When a notiifcation is added and then removed before it is fully processed + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + backgroundExecutor.runAllReady() + mediaDataManager.onNotificationRemoved(KEY) + + // We still make sure to remove it + verify(listener).onMediaDataRemoved(eq(KEY)) + } + /** Helper function to add a media notification and capture the resulting MediaData */ private fun addNotificationAndLoad() { mediaDataManager.onNotificationAdded(KEY, mediaNotification) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt index 997198e116c0..a72634bcb807 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt @@ -61,7 +61,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor @@ -69,6 +68,8 @@ import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.floatThat import org.mockito.Mockito.mock +import org.mockito.Mockito.reset +import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @@ -107,7 +108,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener> @Captor lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener> - @Captor lateinit var newConfig: ArgumentCaptor<Configuration> @Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener> @Captor lateinit var keyguardCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback> @@ -150,7 +150,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { MediaPlayerData.clear() } - @Ignore("b/253229241") @Test fun testPlayerOrdering() { // Test values: key, data, last active time @@ -327,7 +326,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { } } - @Ignore("b/253229241") @Test fun testOrderWithSmartspace_prioritized() { testPlayerOrdering() @@ -335,7 +333,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { // If smartspace is prioritized MediaPlayerData.addMediaRecommendation( SMARTSPACE_KEY, - EMPTY_SMARTSPACE_MEDIA_DATA, + EMPTY_SMARTSPACE_MEDIA_DATA.copy(isActive = true), panel, true, clock @@ -345,7 +343,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertTrue(MediaPlayerData.playerKeys().elementAt(2).isSsMediaRec) } - @Ignore("b/253229241") @Test fun testOrderWithSmartspace_prioritized_updatingVisibleMediaPlayers() { testPlayerOrdering() @@ -362,7 +359,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertTrue(MediaPlayerData.visiblePlayerKeys().elementAt(2).isSsMediaRec) } - @Ignore("b/253229241") @Test fun testOrderWithSmartspace_notPrioritized() { testPlayerOrdering() @@ -370,7 +366,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { // If smartspace is not prioritized MediaPlayerData.addMediaRecommendation( SMARTSPACE_KEY, - EMPTY_SMARTSPACE_MEDIA_DATA, + EMPTY_SMARTSPACE_MEDIA_DATA.copy(isActive = true), panel, false, clock @@ -381,7 +377,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertTrue(MediaPlayerData.playerKeys().elementAt(idx).isSsMediaRec) } - @Ignore("b/253229241") @Test fun testPlayingExistingMediaPlayerFromCarousel_visibleMediaPlayersNotUpdated() { testPlayerOrdering() @@ -419,7 +414,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { ) } - @Ignore("b/253229241") @Test fun testSwipeDismiss_logged() { mediaCarouselController.mediaCarouselScrollHandler.dismissCallback.invoke() @@ -427,7 +421,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logSwipeDismiss() } - @Ignore("b/253229241") @Test fun testSettingsButton_logged() { mediaCarouselController.settingsButton.callOnClick() @@ -435,18 +428,16 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logCarouselSettings() } - @Ignore("b/253229241") @Test fun testLocationChangeQs_logged() { mediaCarouselController.onDesiredLocationChanged( - MediaHierarchyManager.LOCATION_QS, + LOCATION_QS, mediaHostState, animate = false ) - verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_QS) + verify(logger).logCarouselPosition(LOCATION_QS) } - @Ignore("b/253229241") @Test fun testLocationChangeQqs_logged() { mediaCarouselController.onDesiredLocationChanged( @@ -457,7 +448,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_QQS) } - @Ignore("b/253229241") @Test fun testLocationChangeLockscreen_logged() { mediaCarouselController.onDesiredLocationChanged( @@ -468,7 +458,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_LOCKSCREEN) } - @Ignore("b/253229241") @Test fun testLocationChangeDream_logged() { mediaCarouselController.onDesiredLocationChanged( @@ -479,7 +468,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_DREAM_OVERLAY) } - @Ignore("b/253229241") @Test fun testRecommendationRemoved_logged() { val packageName = "smartspace package" @@ -493,7 +481,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logRecommendationRemoved(eq(packageName), eq(instanceId!!)) } - @Ignore("b/253229241") @Test fun testMediaLoaded_ScrollToActivePlayer() { listener.value.onMediaDataLoaded( @@ -551,7 +538,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { ) } - @Ignore("b/253229241") @Test fun testMediaLoadedFromRecommendationCard_ScrollToActivePlayer() { listener.value.onSmartspaceMediaDataLoaded( @@ -595,7 +581,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertEquals(playerIndex, 0) } - @Ignore("b/253229241") @Test fun testRecommendationRemovedWhileNotVisible_updateHostVisibility() { var result = false @@ -607,7 +592,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertEquals(true, result) } - @Ignore("b/253229241") @Test fun testRecommendationRemovedWhileVisible_thenReorders_updateHostVisibility() { var result = false @@ -621,7 +605,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertEquals(true, result) } - @Ignore("b/253229241") @Test fun testGetCurrentVisibleMediaContentIntent() { val clickIntent1 = mock(PendingIntent::class.java) @@ -668,7 +651,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertEquals(mediaCarouselController.getCurrentVisibleMediaContentIntent(), clickIntent2) } - @Ignore("b/253229241") @Test fun testSetCurrentState_UpdatePageIndicatorAlphaWhenSquish() { val delta = 0.0001F @@ -690,7 +672,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(pageIndicator).alpha = floatThat { abs(it - 1.0F) < delta } } - @Ignore("b/253229241") @Test fun testOnConfigChanged_playersAreAddedBack() { listener.value.onMediaDataLoaded( @@ -716,7 +697,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { val playersSize = MediaPlayerData.players().size - configListener.value.onConfigChanged(capture(newConfig)) + configListener.value.onConfigChanged(Configuration()) assertEquals(playersSize, MediaPlayerData.players().size) assertEquals( @@ -796,4 +777,59 @@ class MediaCarouselControllerTest : SysuiTestCase() { job.cancel() } + + @Test + fun testInvisibleToUserAndExpanded_playersNotListening() { + // Add players to carousel. + testPlayerOrdering() + + // Make the carousel visible to user in expanded layout. + mediaCarouselController.currentlyExpanded = true + mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = true + + // panel is the player for each MediaPlayerData. + // Verify that seekbar listening attribute in media control panel is set to true. + verify(panel, times(MediaPlayerData.players().size)).listening = true + + // Make the carousel invisible to user. + mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = false + + // panel is the player for each MediaPlayerData. + // Verify that seekbar listening attribute in media control panel is set to false. + verify(panel, times(MediaPlayerData.players().size)).listening = false + } + + @Test + fun testVisibleToUserAndExpanded_playersListening() { + // Add players to carousel. + testPlayerOrdering() + + // Make the carousel visible to user in expanded layout. + mediaCarouselController.currentlyExpanded = true + mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = true + + // panel is the player for each MediaPlayerData. + // Verify that seekbar listening attribute in media control panel is set to true. + verify(panel, times(MediaPlayerData.players().size)).listening = true + } + + @Test + fun testUMOCollapsed_playersNotListening() { + // Add players to carousel. + testPlayerOrdering() + + // Make the carousel in collapsed layout. + mediaCarouselController.currentlyExpanded = false + + // panel is the player for each MediaPlayerData. + // Verify that seekbar listening attribute in media control panel is set to false. + verify(panel, times(MediaPlayerData.players().size)).listening = false + + // Make the carousel visible to user. + reset(panel) + mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = true + + // Verify that seekbar listening attribute in media control panel is set to false. + verify(panel, times(MediaPlayerData.players().size)).listening = false + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt index 2f7eac2ad4ae..af91cdb1522c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt @@ -33,6 +33,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.floatThat import org.mockito.Mock +import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @@ -139,14 +140,12 @@ class MediaViewControllerTest : SysuiTestCase() { whenever(controlWidgetState.y).thenReturn(150F) whenever(controlWidgetState.height).thenReturn(20) // in current beizer, when the progress reach 0.38, the result will be 0.5 - mediaViewController.squishViewState(mockViewState, 119F / 200F) - verify(detailWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta } - mediaViewController.squishViewState(mockViewState, 150F / 200F) - verify(detailWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta } mediaViewController.squishViewState(mockViewState, 181.4F / 200F) verify(controlWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta } + verify(detailWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta } mediaViewController.squishViewState(mockViewState, 200F / 200F) verify(controlWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta } + verify(detailWidgetState, times(2)).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta } } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt index bc67df6507fc..5f206b373610 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt @@ -13,8 +13,9 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @SmallTest -internal class FloatingRotationButtonPositionCalculatorTest(private val testCase: TestCase) - : SysuiTestCase() { +internal class FloatingRotationButtonPositionCalculatorTest( + private val testCase: TestCase, +) : SysuiTestCase() { @Test fun calculatePosition() { @@ -34,11 +35,18 @@ internal class FloatingRotationButtonPositionCalculatorTest(private val testCase val expectedPosition: Position ) { override fun toString(): String = - "when calculator = $calculator, " + - "rotation = $rotation, " + - "taskbarVisible = $taskbarVisible, " + - "taskbarStashed = $taskbarStashed - " + - "expected $expectedPosition" + buildString { + append("when calculator = ") + append(when (calculator) { + posLeftCalculator -> "LEFT" + posRightCalculator -> "RIGHT" + else -> error("Unknown calculator: $calculator") + }) + append(", rotation = $rotation") + append(", taskbarVisible = $taskbarVisible") + append(", taskbarStashed = $taskbarStashed") + append(" - expected $expectedPosition") + } } companion object { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt index 3281fa9bd8a4..e222542e5c53 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt @@ -35,6 +35,7 @@ import com.android.systemui.qs.tiles.DeviceControlsTile import com.android.systemui.qs.tiles.DndTile import com.android.systemui.qs.tiles.DreamTile import com.android.systemui.qs.tiles.FlashlightTile +import com.android.systemui.qs.tiles.FontScalingTile import com.android.systemui.qs.tiles.HotspotTile import com.android.systemui.qs.tiles.InternetTile import com.android.systemui.qs.tiles.LocationTile @@ -51,14 +52,15 @@ import com.android.systemui.qs.tiles.UiModeNightTile import com.android.systemui.qs.tiles.WorkModeTile import com.android.systemui.util.leak.GarbageMonitor import com.google.common.truth.Truth.assertThat +import javax.inject.Provider import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Answers import org.mockito.Mock import org.mockito.Mockito.inOrder -import org.mockito.MockitoAnnotations import org.mockito.Mockito.`when` as whenever +import org.mockito.MockitoAnnotations private val specMap = mapOf( "internet" to InternetTile::class.java, @@ -87,7 +89,8 @@ private val specMap = mapOf( "qr_code_scanner" to QRCodeScannerTile::class.java, "onehanded" to OneHandedModeTile::class.java, "color_correction" to ColorCorrectionTile::class.java, - "dream" to DreamTile::class.java + "dream" to DreamTile::class.java, + "font_scaling" to FontScalingTile::class.java ) @RunWith(AndroidTestingRunner::class) @@ -126,6 +129,7 @@ class QSFactoryImplTest : SysuiTestCase() { @Mock private lateinit var oneHandedModeTile: OneHandedModeTile @Mock private lateinit var colorCorrectionTile: ColorCorrectionTile @Mock private lateinit var dreamTile: DreamTile + @Mock private lateinit var fontScalingTile: FontScalingTile private lateinit var factory: QSFactoryImpl @@ -137,39 +141,43 @@ class QSFactoryImplTest : SysuiTestCase() { whenever(qsHost.userContext).thenReturn(mContext) whenever(customTileBuilder.build()).thenReturn(customTile) + val tileMap = mutableMapOf<String, Provider<QSTileImpl<*>>>( + "internet" to Provider { internetTile }, + "bt" to Provider { bluetoothTile }, + "dnd" to Provider { dndTile }, + "inversion" to Provider { colorInversionTile }, + "airplane" to Provider { airplaneTile }, + "work" to Provider { workTile }, + "rotation" to Provider { rotationTile }, + "flashlight" to Provider { flashlightTile }, + "location" to Provider { locationTile }, + "cast" to Provider { castTile }, + "hotspot" to Provider { hotspotTile }, + "battery" to Provider { batterySaverTile }, + "saver" to Provider { dataSaverTile }, + "night" to Provider { nightDisplayTile }, + "nfc" to Provider { nfcTile }, + "dark" to Provider { darkModeTile }, + "screenrecord" to Provider { screenRecordTile }, + "reduce_brightness" to Provider { reduceBrightColorsTile }, + "cameratoggle" to Provider { cameraToggleTile }, + "mictoggle" to Provider { microphoneToggleTile }, + "controls" to Provider { deviceControlsTile }, + "alarm" to Provider { alarmTile }, + "wallet" to Provider { quickAccessWalletTile }, + "qr_code_scanner" to Provider { qrCodeScannerTile }, + "onehanded" to Provider { oneHandedModeTile }, + "color_correction" to Provider { colorCorrectionTile }, + "dream" to Provider { dreamTile }, + "font_scaling" to Provider { fontScalingTile } + ) + factory = QSFactoryImpl( { qsHost }, { customTileBuilder }, - { internetTile }, - { bluetoothTile }, - { dndTile }, - { colorInversionTile }, - { airplaneTile }, - { workTile }, - { rotationTile }, - { flashlightTile }, - { locationTile }, - { castTile }, - { hotspotTile }, - { batterySaverTile }, - { dataSaverTile }, - { nightDisplayTile }, - { nfcTile }, - { memoryTile }, - { darkModeTile }, - { screenRecordTile }, - { reduceBrightColorsTile }, - { cameraToggleTile }, - { microphoneToggleTile }, - { deviceControlsTile }, - { alarmTile }, - { quickAccessWalletTile }, - { qrCodeScannerTile }, - { oneHandedModeTile }, - { colorCorrectionTile }, - { dreamTile } + tileMap, ) - // When adding/removing tiles, fix also [specMap] + // When adding/removing tiles, fix also [specMap] and [tileMap] } @Test @@ -205,4 +213,4 @@ class QSFactoryImplTest : SysuiTestCase() { inOrder.verify(tile).initialize() inOrder.verify(tile).postStale() } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt new file mode 100644 index 000000000000..57abae0889ca --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.qs.tiles.dialog + +import android.os.Handler +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.internal.logging.MetricsLogger +import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.classifier.FalsingManagerFake +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.qs.QSTileHost +import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.qs.tiles.FontScalingTile +import com.android.systemui.util.settings.FakeSettings +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +@SmallTest +class FontScalingTileTest : SysuiTestCase() { + @Mock private lateinit var qsHost: QSTileHost + @Mock private lateinit var metricsLogger: MetricsLogger + @Mock private lateinit var statusBarStateController: StatusBarStateController + @Mock private lateinit var activityStarter: ActivityStarter + @Mock private lateinit var qsLogger: QSLogger + @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator + + private lateinit var testableLooper: TestableLooper + private lateinit var fontScalingTile: FontScalingTile + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + testableLooper = TestableLooper.get(this) + `when`(qsHost.getContext()).thenReturn(mContext) + fontScalingTile = + FontScalingTile( + qsHost, + testableLooper.looper, + Handler(testableLooper.looper), + FalsingManagerFake(), + metricsLogger, + statusBarStateController, + activityStarter, + qsLogger, + dialogLaunchAnimator, + FakeSettings() + ) + fontScalingTile.initialize() + } + + @Test + fun isNotAvailable_whenNotSupportedDevice_returnsFalse() { + val isAvailable = fontScalingTile.isAvailable() + + assertThat(isAvailable).isFalse() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java index ea0e454f0b5d..9acd47e4378f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java @@ -16,14 +16,13 @@ package com.android.systemui.reardisplay; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import android.hardware.devicestate.DeviceStateManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.view.View; +import android.widget.TextView; import androidx.test.filters.SmallTest; @@ -37,8 +36,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import java.util.concurrent.Executor; - @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -63,9 +60,11 @@ public class RearDisplayDialogControllerTest extends SysuiTestCase { controller.showRearDisplayDialog(CLOSED_BASE_STATE); assertTrue(controller.mRearDisplayEducationDialog.isShowing()); - View deviceOpenedWarningTextView = controller.mRearDisplayEducationDialog.findViewById( - R.id.rear_display_warning_text_view); - assertNull(deviceOpenedWarningTextView); + TextView deviceClosedTitleTextView = controller.mRearDisplayEducationDialog.findViewById( + R.id.rear_display_title_text_view); + assertEquals(deviceClosedTitleTextView.getText().toString(), + getContext().getResources().getString( + R.string.rear_display_folded_bottom_sheet_title)); } @Test @@ -79,9 +78,11 @@ public class RearDisplayDialogControllerTest extends SysuiTestCase { controller.showRearDisplayDialog(OPEN_BASE_STATE); assertTrue(controller.mRearDisplayEducationDialog.isShowing()); - View deviceOpenedWarningTextView = controller.mRearDisplayEducationDialog.findViewById( - R.id.rear_display_warning_text_view); - assertNotNull(deviceOpenedWarningTextView); + TextView deviceClosedTitleTextView = controller.mRearDisplayEducationDialog.findViewById( + R.id.rear_display_title_text_view); + assertEquals(deviceClosedTitleTextView.getText().toString(), + getContext().getResources().getString( + R.string.rear_display_unfolded_bottom_sheet_title)); } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt index 1fa2ace955b0..c40c287df9e8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt @@ -38,7 +38,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.util.ScreenshotRequest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags.SCREENSHOT_METADATA +import com.android.systemui.flags.Flags.SCREENSHOT_METADATA_REFACTOR import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER @@ -126,7 +126,7 @@ class TakeScreenshotServiceTest : SysuiTestCase() { // Flipped in selected test cases flags.set(SCREENSHOT_WORK_PROFILE_POLICY, false) - flags.set(SCREENSHOT_METADATA, false) + flags.set(SCREENSHOT_METADATA_REFACTOR, false) service.attach( mContext, @@ -183,7 +183,7 @@ class TakeScreenshotServiceTest : SysuiTestCase() { @Test fun takeScreenshotFullscreen_screenshotDataEnabled() { - flags.set(SCREENSHOT_METADATA, true) + flags.set(SCREENSHOT_METADATA_REFACTOR, true) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) @@ -260,7 +260,7 @@ class TakeScreenshotServiceTest : SysuiTestCase() { @Test fun takeScreenshotFullscreen_userLocked() { - flags.set(SCREENSHOT_METADATA, true) + flags.set(SCREENSHOT_METADATA_REFACTOR, true) whenever(userManager.isUserUnlocked).thenReturn(false) @@ -302,7 +302,7 @@ class TakeScreenshotServiceTest : SysuiTestCase() { @Test fun takeScreenshotFullscreen_screenCaptureDisabled_allUsers() { - flags.set(SCREENSHOT_METADATA, true) + flags.set(SCREENSHOT_METADATA_REFACTOR, true) whenever(devicePolicyManager.getScreenCaptureDisabled(isNull(), eq(UserHandle.USER_ALL))) .thenReturn(true) @@ -353,7 +353,7 @@ class TakeScreenshotServiceTest : SysuiTestCase() { @Test fun takeScreenshotFullscreen_userLocked_metadataDisabled() { - flags.set(SCREENSHOT_METADATA, false) + flags.set(SCREENSHOT_METADATA_REFACTOR, false) whenever(userManager.isUserUnlocked).thenReturn(false) val request = @@ -394,7 +394,7 @@ class TakeScreenshotServiceTest : SysuiTestCase() { @Test fun takeScreenshotFullscreen_screenCaptureDisabled_allUsers_metadataDisabled() { - flags.set(SCREENSHOT_METADATA, false) + flags.set(SCREENSHOT_METADATA_REFACTOR, false) whenever(devicePolicyManager.getScreenCaptureDisabled(isNull(), eq(UserHandle.USER_ALL))) .thenReturn(true) @@ -445,7 +445,7 @@ class TakeScreenshotServiceTest : SysuiTestCase() { @Test fun takeScreenshot_workProfile_nullBitmap_metadataDisabled() { - flags.set(SCREENSHOT_METADATA, false) + flags.set(SCREENSHOT_METADATA_REFACTOR, false) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) @@ -487,7 +487,7 @@ class TakeScreenshotServiceTest : SysuiTestCase() { } @Test fun takeScreenshot_workProfile_nullBitmap() { - flags.set(SCREENSHOT_METADATA, true) + flags.set(SCREENSHOT_METADATA_REFACTOR, true) val request = ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt index 78bebb92dc70..d01edccb6a82 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt @@ -18,8 +18,6 @@ package com.android.systemui.shared.clocks import android.content.ContentResolver import android.content.Context import android.graphics.drawable.Drawable -import android.os.Handler -import android.os.UserHandle import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -34,6 +32,9 @@ import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq import junit.framework.Assert.assertEquals import junit.framework.Assert.fail +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope import org.json.JSONException import org.junit.Before import org.junit.Rule @@ -49,19 +50,19 @@ import org.mockito.junit.MockitoJUnit class ClockRegistryTest : SysuiTestCase() { @JvmField @Rule val mockito = MockitoJUnit.rule() + private lateinit var dispatcher: CoroutineDispatcher + private lateinit var scope: TestScope + @Mock private lateinit var mockContext: Context @Mock private lateinit var mockPluginManager: PluginManager @Mock private lateinit var mockClock: ClockController @Mock private lateinit var mockDefaultClock: ClockController @Mock private lateinit var mockThumbnail: Drawable - @Mock private lateinit var mockHandler: Handler @Mock private lateinit var mockContentResolver: ContentResolver private lateinit var fakeDefaultProvider: FakeClockPlugin private lateinit var pluginListener: PluginListener<ClockProviderPlugin> private lateinit var registry: ClockRegistry - private var settingValue: ClockSettings? = null - companion object { private fun failFactory(): ClockController { fail("Unexpected call to createClock") @@ -99,6 +100,9 @@ class ClockRegistryTest : SysuiTestCase() { @Before fun setUp() { + dispatcher = StandardTestDispatcher() + scope = TestScope(dispatcher) + fakeDefaultProvider = FakeClockPlugin() .addClock(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME, { mockDefaultClock }, { mockThumbnail }) whenever(mockContext.contentResolver).thenReturn(mockContentResolver) @@ -107,15 +111,22 @@ class ClockRegistryTest : SysuiTestCase() { registry = object : ClockRegistry( mockContext, mockPluginManager, - mockHandler, + scope = scope.backgroundScope, + mainDispatcher = dispatcher, + bgDispatcher = dispatcher, isEnabled = true, - userHandle = UserHandle.USER_ALL, - defaultClockProvider = fakeDefaultProvider + handleAllUsers = true, + defaultClockProvider = fakeDefaultProvider, ) { - override var settings: ClockSettings? - get() = settingValue - set(value) { settingValue = value } + override fun querySettings() { } + override fun applySettings(value: ClockSettings?) { + settings = value + } + // Unit Test does not validate threading + override fun assertMainThread() {} + override fun assertNotMainThread() {} } + registry.registerListeners() verify(mockPluginManager) .addPluginListener(captor.capture(), eq(ClockProviderPlugin::class.java), eq(true)) @@ -187,16 +198,16 @@ class ClockRegistryTest : SysuiTestCase() { .addClock("clock_1", "clock 1") .addClock("clock_2", "clock 2") - settingValue = ClockSettings("clock_3", null, null) val plugin2 = FakeClockPlugin() .addClock("clock_3", "clock 3", { mockClock }) .addClock("clock_4", "clock 4") + registry.applySettings(ClockSettings("clock_3", null)) pluginListener.onPluginConnected(plugin1, mockContext) pluginListener.onPluginConnected(plugin2, mockContext) val clock = registry.createCurrentClock() - assertEquals(clock, mockClock) + assertEquals(mockClock, clock) } @Test @@ -205,11 +216,11 @@ class ClockRegistryTest : SysuiTestCase() { .addClock("clock_1", "clock 1") .addClock("clock_2", "clock 2") - settingValue = ClockSettings("clock_3", null, null) val plugin2 = FakeClockPlugin() .addClock("clock_3", "clock 3") .addClock("clock_4", "clock 4") + registry.applySettings(ClockSettings("clock_3", null)) pluginListener.onPluginConnected(plugin1, mockContext) pluginListener.onPluginConnected(plugin2, mockContext) pluginListener.onPluginDisconnected(plugin2) @@ -224,11 +235,11 @@ class ClockRegistryTest : SysuiTestCase() { .addClock("clock_1", "clock 1") .addClock("clock_2", "clock 2") - settingValue = ClockSettings("clock_3", null, null) val plugin2 = FakeClockPlugin() .addClock("clock_3", "clock 3", { mockClock }) .addClock("clock_4", "clock 4") + registry.applySettings(ClockSettings("clock_3", null)) pluginListener.onPluginConnected(plugin1, mockContext) pluginListener.onPluginConnected(plugin2, mockContext) @@ -244,7 +255,7 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun jsonDeserialization_gotExpectedObject() { - val expected = ClockSettings("ID", null, 500) + val expected = ClockSettings("ID", null).apply { _applied_timestamp = 500 } val actual = ClockSettings.deserialize("""{ "clockId":"ID", "_applied_timestamp":500 @@ -254,14 +265,14 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun jsonDeserialization_noTimestamp_gotExpectedObject() { - val expected = ClockSettings("ID", null, null) + val expected = ClockSettings("ID", null) val actual = ClockSettings.deserialize("{\"clockId\":\"ID\"}") assertEquals(expected, actual) } @Test fun jsonDeserialization_nullTimestamp_gotExpectedObject() { - val expected = ClockSettings("ID", null, null) + val expected = ClockSettings("ID", null) val actual = ClockSettings.deserialize("""{ "clockId":"ID", "_applied_timestamp":null @@ -271,7 +282,7 @@ class ClockRegistryTest : SysuiTestCase() { @Test(expected = JSONException::class) fun jsonDeserialization_noId_threwException() { - val expected = ClockSettings("ID", null, 500) + val expected = ClockSettings(null, null).apply { _applied_timestamp = 500 } val actual = ClockSettings.deserialize("{\"_applied_timestamp\":500}") assertEquals(expected, actual) } @@ -279,14 +290,15 @@ class ClockRegistryTest : SysuiTestCase() { @Test fun jsonSerialization_gotExpectedString() { val expected = "{\"clockId\":\"ID\",\"_applied_timestamp\":500}" - val actual = ClockSettings.serialize(ClockSettings("ID", null, 500)) + val actual = ClockSettings.serialize(ClockSettings("ID", null) + .apply { _applied_timestamp = 500 }) assertEquals(expected, actual) } @Test fun jsonSerialization_noTimestamp_gotExpectedString() { val expected = "{\"clockId\":\"ID\"}" - val actual = ClockSettings.serialize(ClockSettings("ID", null, null)) + val actual = ClockSettings.serialize(ClockSettings("ID", null)) assertEquals(expected, actual) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java index 9eccbb6303ab..aa1636d8a030 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java @@ -249,6 +249,21 @@ public class ConditionMonitorTest extends SysuiTestCase { } @Test + public void addCallback_preCondition_noConditions_reportAllConditionsMet() { + final Monitor + monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(mCondition1))); + final Monitor.Callback callback = mock( + Monitor.Callback.class); + + monitor.addSubscription(new Monitor.Subscription.Builder(callback).build()); + mExecutor.runAllReady(); + verify(callback, never()).onConditionsChanged(true); + mCondition1.fakeUpdateCondition(true); + mExecutor.runAllReady(); + verify(callback).onConditionsChanged(true); + } + + @Test public void removeCallback_noFailureOnDoubleRemove() { final Condition condition = mock( Condition.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java index 03af527eb9f3..fbec95bcc874 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java @@ -741,7 +741,7 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { } @Test - public void testShouldFullScreen_snoozed_occluding_withStrictRules() throws Exception { + public void testShouldNotFullScreen_snoozed_occluding_withStrictRules() throws Exception { when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true); NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); when(mPowerManager.isInteractive()).thenReturn(true); @@ -753,16 +753,41 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { when(mKeyguardStateController.isOccluded()).thenReturn(true); assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry)) - .isEqualTo(FullScreenIntentDecision.FSI_KEYGUARD_OCCLUDED); + .isEqualTo(FullScreenIntentDecision.NO_FSI_EXPECTED_TO_HUN); assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) - .isTrue(); - verify(mLogger, never()).logNoFullscreen(any(), any()); + .isFalse(); + verify(mLogger).logNoFullscreen(entry, "Expected to HUN"); verify(mLogger, never()).logNoFullscreenWarning(any(), any()); - verify(mLogger).logFullscreen(entry, "Expected not to HUN while keyguard occluded"); + verify(mLogger, never()).logFullscreen(any(), any()); } @Test - public void testShouldFullScreen_snoozed_lockedShade_withStrictRules() throws Exception { + public void testShouldHeadsUp_snoozed_occluding_withStrictRules() throws Exception { + when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true); + NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); + when(mPowerManager.isInteractive()).thenReturn(true); + when(mPowerManager.isScreenOn()).thenReturn(true); + when(mDreamManager.isDreaming()).thenReturn(false); + when(mStatusBarStateController.getState()).thenReturn(SHADE); + when(mHeadsUpManager.isSnoozed("a")).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isOccluded()).thenReturn(true); + + assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue(); + + verify(mLogger).logHeadsUpPackageSnoozeBypassedHasFsi(entry); + verify(mLogger, never()).logHeadsUp(any()); + + assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1); + UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0); + assertThat(fakeUiEvent.eventId).isEqualTo( + NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI.getId()); + assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid()); + assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName()); + } + + @Test + public void testShouldNotFullScreen_snoozed_lockedShade_withStrictRules() throws Exception { when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true); NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); when(mPowerManager.isInteractive()).thenReturn(true); @@ -774,12 +799,37 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { when(mKeyguardStateController.isOccluded()).thenReturn(false); assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry)) - .isEqualTo(FullScreenIntentDecision.FSI_LOCKED_SHADE); + .isEqualTo(FullScreenIntentDecision.NO_FSI_EXPECTED_TO_HUN); assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) - .isTrue(); - verify(mLogger, never()).logNoFullscreen(any(), any()); + .isFalse(); + verify(mLogger).logNoFullscreen(entry, "Expected to HUN"); verify(mLogger, never()).logNoFullscreenWarning(any(), any()); - verify(mLogger).logFullscreen(entry, "Keyguard is showing and not occluded"); + verify(mLogger, never()).logFullscreen(any(), any()); + } + + @Test + public void testShouldHeadsUp_snoozed_lockedShade_withStrictRules() throws Exception { + when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true); + NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); + when(mPowerManager.isInteractive()).thenReturn(true); + when(mPowerManager.isScreenOn()).thenReturn(true); + when(mDreamManager.isDreaming()).thenReturn(false); + when(mStatusBarStateController.getState()).thenReturn(SHADE_LOCKED); + when(mHeadsUpManager.isSnoozed("a")).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isOccluded()).thenReturn(false); + + assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue(); + + verify(mLogger).logHeadsUpPackageSnoozeBypassedHasFsi(entry); + verify(mLogger, never()).logHeadsUp(any()); + + assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1); + UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0); + assertThat(fakeUiEvent.eventId).isEqualTo( + NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI.getId()); + assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid()); + assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName()); } @Test @@ -795,21 +845,41 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { when(mKeyguardStateController.isOccluded()).thenReturn(false); assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry)) - .isEqualTo(FullScreenIntentDecision.NO_FSI_NO_HUN_OR_KEYGUARD); + .isEqualTo(FullScreenIntentDecision.NO_FSI_EXPECTED_TO_HUN); assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) .isFalse(); - verify(mLogger, never()).logNoFullscreen(any(), any()); - verify(mLogger).logNoFullscreenWarning(entry, "Expected not to HUN while not on keyguard"); + verify(mLogger).logNoFullscreen(entry, "Expected to HUN"); + verify(mLogger, never()).logNoFullscreenWarning(any(), any()); verify(mLogger, never()).logFullscreen(any(), any()); + } + + @Test + public void testShouldHeadsUp_snoozed_unlocked_withStrictRules() throws Exception { + when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true); + NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); + when(mPowerManager.isInteractive()).thenReturn(true); + when(mPowerManager.isScreenOn()).thenReturn(true); + when(mDreamManager.isDreaming()).thenReturn(false); + when(mStatusBarStateController.getState()).thenReturn(SHADE); + when(mHeadsUpManager.isSnoozed("a")).thenReturn(true); + when(mKeyguardStateController.isShowing()).thenReturn(false); + when(mKeyguardStateController.isOccluded()).thenReturn(false); + + assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue(); + + verify(mLogger).logHeadsUpPackageSnoozeBypassedHasFsi(entry); + verify(mLogger, never()).logHeadsUp(any()); assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1); UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0); assertThat(fakeUiEvent.eventId).isEqualTo( - NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD.getId()); + NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI.getId()); assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid()); assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName()); } + /* TODO: Verify the FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD UiEvent some other way. */ + /** * Bubbles can happen. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java index 6c83e9f88d63..14a925a737b9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java @@ -19,8 +19,10 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.BroadcastReceiver; import android.content.Intent; @@ -32,6 +34,8 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import org.junit.Before; import org.junit.Test; @@ -46,12 +50,15 @@ import org.mockito.MockitoAnnotations; public class SystemUIDialogTest extends SysuiTestCase { @Mock + private FeatureFlags mFeatureFlags; + @Mock private BroadcastDispatcher mBroadcastDispatcher; @Before public void setup() { MockitoAnnotations.initMocks(this); + mDependency.injectTestDependency(FeatureFlags.class, mFeatureFlags); mDependency.injectTestDependency(BroadcastDispatcher.class, mBroadcastDispatcher); } @@ -86,4 +93,20 @@ public class SystemUIDialogTest extends SysuiTestCase { verify(mBroadcastDispatcher, never()).unregisterReceiver(any()); assertFalse(dialog.isShowing()); } + + @Test + public void usePredictiveBackAnimFlag() { + when(mFeatureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM)) + .thenReturn(true); + final SystemUIDialog dialog = new SystemUIDialog(mContext); + + dialog.show(); + + assertTrue(dialog.isShowing()); + verify(mFeatureFlags, atLeast(1)) + .isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM); + + dialog.dismiss(); + assertFalse(dialog.isShowing()); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt index abb45619e1dd..f0f213bc0d58 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt @@ -26,8 +26,8 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectio import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel -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.shared.model.WifiNetworkModel import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt index c02ca01cedc4..cd4d8472763f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt @@ -32,8 +32,8 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameMode import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType -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.shared.model.WifiNetworkModel import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt index 673e5599fce7..8090205a0c1f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt @@ -44,8 +44,8 @@ import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConn import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger -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.shared.model.WifiNetworkModel import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq @@ -896,21 +896,31 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() { // Subscription 1 private const val SUB_1_ID = 1 + private val GROUP_1 = ParcelUuid(UUID.randomUUID()) private val SUB_1 = mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) - whenever(it.groupUuid).thenReturn(ParcelUuid(UUID.randomUUID())) + whenever(it.groupUuid).thenReturn(GROUP_1) } - private val MODEL_1 = SubscriptionModel(subscriptionId = SUB_1_ID) + private val MODEL_1 = + SubscriptionModel( + subscriptionId = SUB_1_ID, + groupUuid = GROUP_1, + ) // Subscription 2 private const val SUB_2_ID = 2 + private val GROUP_2 = ParcelUuid(UUID.randomUUID()) private val SUB_2 = mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) - whenever(it.groupUuid).thenReturn(ParcelUuid(UUID.randomUUID())) + whenever(it.groupUuid).thenReturn(GROUP_2) } - private val MODEL_2 = SubscriptionModel(subscriptionId = SUB_2_ID) + private val MODEL_2 = + SubscriptionModel( + subscriptionId = SUB_2_ID, + groupUuid = GROUP_2, + ) // Subs 3 and 4 are considered to be in the same group ------------------------------------ private val GROUP_ID_3_4 = ParcelUuid(UUID.randomUUID()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index f8a978300dd3..bbca0011483f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor +import android.os.ParcelUuid import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import androidx.test.filters.SmallTest import com.android.settingslib.mobile.MobileMappings @@ -34,6 +35,7 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat +import java.util.UUID import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -104,6 +106,21 @@ class MobileIconsInteractorTest : SysuiTestCase() { job.cancel() } + // Based on the logic from the old pipeline, we'll never filter subs when there are more than 2 + @Test + fun filteredSubscriptions_moreThanTwo_doesNotFilter() = + testScope.runTest { + connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP)) + connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID) + + var latest: List<SubscriptionModel>? = null + val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP)) + + job.cancel() + } + @Test fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() = testScope.runTest { @@ -118,10 +135,50 @@ class MobileIconsInteractorTest : SysuiTestCase() { } @Test - fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_3() = + fun filteredSubscriptions_opportunistic_differentGroups_doesNotFilter() = testScope.runTest { connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP)) connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID) + + var latest: List<SubscriptionModel>? = null + val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo(listOf(SUB_3_OPP, SUB_4_OPP)) + + job.cancel() + } + + @Test + fun filteredSubscriptions_opportunistic_nonGrouped_doesNotFilter() = + testScope.runTest { + val (sub1, sub2) = + createSubscriptionPair( + subscriptionIds = Pair(SUB_1_ID, SUB_2_ID), + opportunistic = Pair(true, true), + grouped = false, + ) + connectionsRepository.setSubscriptions(listOf(sub1, sub2)) + connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID) + + var latest: List<SubscriptionModel>? = null + val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo(listOf(sub1, sub2)) + + job.cancel() + } + + @Test + fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_3() = + testScope.runTest { + val (sub3, sub4) = + createSubscriptionPair( + subscriptionIds = Pair(SUB_3_ID, SUB_4_ID), + opportunistic = Pair(true, true), + grouped = true, + ) + connectionsRepository.setSubscriptions(listOf(sub3, sub4)) + connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID) whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) .thenReturn(false) @@ -129,15 +186,21 @@ class MobileIconsInteractorTest : SysuiTestCase() { val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this) // Filtered subscriptions should show the active one when the config is false - assertThat(latest).isEqualTo(listOf(SUB_3_OPP)) + assertThat(latest).isEqualTo(listOf(sub3)) job.cancel() } @Test - fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_4() = + fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_4() = testScope.runTest { - connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP)) + val (sub3, sub4) = + createSubscriptionPair( + subscriptionIds = Pair(SUB_3_ID, SUB_4_ID), + opportunistic = Pair(true, true), + grouped = true, + ) + connectionsRepository.setSubscriptions(listOf(sub3, sub4)) connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID) whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) .thenReturn(false) @@ -146,15 +209,21 @@ class MobileIconsInteractorTest : SysuiTestCase() { val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this) // Filtered subscriptions should show the active one when the config is false - assertThat(latest).isEqualTo(listOf(SUB_4_OPP)) + assertThat(latest).isEqualTo(listOf(sub4)) job.cancel() } @Test - fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_active_1() = + fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_active_1() = testScope.runTest { - connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP)) + val (sub1, sub3) = + createSubscriptionPair( + subscriptionIds = Pair(SUB_1_ID, SUB_3_ID), + opportunistic = Pair(false, true), + grouped = true, + ) + connectionsRepository.setSubscriptions(listOf(sub1, sub3)) connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID) whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) .thenReturn(true) @@ -164,15 +233,21 @@ class MobileIconsInteractorTest : SysuiTestCase() { // Filtered subscriptions should show the primary (non-opportunistic) if the config is // true - assertThat(latest).isEqualTo(listOf(SUB_1)) + assertThat(latest).isEqualTo(listOf(sub1)) job.cancel() } @Test - fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_nonActive_1() = + fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_nonActive_1() = testScope.runTest { - connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP)) + val (sub1, sub3) = + createSubscriptionPair( + subscriptionIds = Pair(SUB_1_ID, SUB_3_ID), + opportunistic = Pair(false, true), + grouped = true, + ) + connectionsRepository.setSubscriptions(listOf(sub1, sub3)) connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID) whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) .thenReturn(true) @@ -182,7 +257,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { // Filtered subscriptions should show the primary (non-opportunistic) if the config is // true - assertThat(latest).isEqualTo(listOf(SUB_1)) + assertThat(latest).isEqualTo(listOf(sub1)) job.cancel() } @@ -642,6 +717,33 @@ class MobileIconsInteractorTest : SysuiTestCase() { job.cancel() } + /** + * Convenience method for creating a pair of subscriptions to test the filteredSubscriptions + * flow. + */ + private fun createSubscriptionPair( + subscriptionIds: Pair<Int, Int>, + opportunistic: Pair<Boolean, Boolean> = Pair(false, false), + grouped: Boolean = false, + ): Pair<SubscriptionModel, SubscriptionModel> { + val groupUuid = if (grouped) ParcelUuid(UUID.randomUUID()) else null + val sub1 = + SubscriptionModel( + subscriptionId = subscriptionIds.first, + isOpportunistic = opportunistic.first, + groupUuid = groupUuid, + ) + + val sub2 = + SubscriptionModel( + subscriptionId = subscriptionIds.second, + isOpportunistic = opportunistic.second, + groupUuid = groupUuid, + ) + + return Pair(sub1, sub2) + } + companion object { private val tableLogBuffer = TableLogBuffer(8, "MobileIconsInteractorTest", FakeSystemClock()) @@ -655,11 +757,21 @@ class MobileIconsInteractorTest : SysuiTestCase() { private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, tableLogBuffer) private const val SUB_3_ID = 3 - private val SUB_3_OPP = SubscriptionModel(subscriptionId = SUB_3_ID, isOpportunistic = true) + private val SUB_3_OPP = + SubscriptionModel( + subscriptionId = SUB_3_ID, + isOpportunistic = true, + groupUuid = ParcelUuid(UUID.randomUUID()), + ) private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, tableLogBuffer) private const val SUB_4_ID = 4 - private val SUB_4_OPP = SubscriptionModel(subscriptionId = SUB_4_ID, isOpportunistic = true) + private val SUB_4_OPP = + SubscriptionModel( + subscriptionId = SUB_4_ID, + isOpportunistic = true, + groupUuid = ParcelUuid(UUID.randomUUID()), + ) private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, tableLogBuffer) } } 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 index f5837d698c51..1bf431b4ea13 100644 --- 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 @@ -17,8 +17,8 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt index 3c4e85bd231e..9cf08c03b5d1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepositoryTest.kt @@ -19,7 +19,7 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt index 7099f1f0af2d..db791bbb1f1f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt @@ -36,8 +36,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -83,13 +83,14 @@ class WifiRepositoryImplTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) whenever( - broadcastDispatcher.broadcastFlow( - any(), - nullable(), - anyInt(), - nullable(), + broadcastDispatcher.broadcastFlow( + any(), + nullable(), + anyInt(), + nullable(), + ) ) - ).thenReturn(flowOf(Unit)) + .thenReturn(flowOf(Unit)) executor = FakeExecutor(FakeSystemClock()) scope = CoroutineScope(IMMEDIATE) underTest = createRepo() @@ -101,150 +102,152 @@ class WifiRepositoryImplTest : SysuiTestCase() { } @Test - fun isWifiEnabled_initiallyGetsWifiManagerValue() = runBlocking(IMMEDIATE) { - whenever(wifiManager.isWifiEnabled).thenReturn(true) + fun isWifiEnabled_initiallyGetsWifiManagerValue() = + runBlocking(IMMEDIATE) { + whenever(wifiManager.isWifiEnabled).thenReturn(true) - underTest = createRepo() + underTest = createRepo() - assertThat(underTest.isWifiEnabled.value).isTrue() - } + assertThat(underTest.isWifiEnabled.value).isTrue() + } @Test - fun isWifiEnabled_networkCapabilitiesChanged_valueUpdated() = runBlocking(IMMEDIATE) { - // We need to call launch on the flows so that they start updating - val networkJob = underTest.wifiNetwork.launchIn(this) - val enabledJob = underTest.isWifiEnabled.launchIn(this) + fun isWifiEnabled_networkCapabilitiesChanged_valueUpdated() = + runBlocking(IMMEDIATE) { + // We need to call launch on the flows so that they start updating + val networkJob = underTest.wifiNetwork.launchIn(this) + val enabledJob = underTest.isWifiEnabled.launchIn(this) - whenever(wifiManager.isWifiEnabled).thenReturn(true) - getNetworkCallback().onCapabilitiesChanged( - NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO) - ) + whenever(wifiManager.isWifiEnabled).thenReturn(true) + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)) - assertThat(underTest.isWifiEnabled.value).isTrue() + assertThat(underTest.isWifiEnabled.value).isTrue() - whenever(wifiManager.isWifiEnabled).thenReturn(false) - getNetworkCallback().onCapabilitiesChanged( - NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO) - ) + whenever(wifiManager.isWifiEnabled).thenReturn(false) + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)) - assertThat(underTest.isWifiEnabled.value).isFalse() + assertThat(underTest.isWifiEnabled.value).isFalse() - networkJob.cancel() - enabledJob.cancel() - } + networkJob.cancel() + enabledJob.cancel() + } @Test - fun isWifiEnabled_networkLost_valueUpdated() = runBlocking(IMMEDIATE) { - // We need to call launch on the flows so that they start updating - val networkJob = underTest.wifiNetwork.launchIn(this) - val enabledJob = underTest.isWifiEnabled.launchIn(this) + fun isWifiEnabled_networkLost_valueUpdated() = + runBlocking(IMMEDIATE) { + // We need to call launch on the flows so that they start updating + val networkJob = underTest.wifiNetwork.launchIn(this) + val enabledJob = underTest.isWifiEnabled.launchIn(this) - whenever(wifiManager.isWifiEnabled).thenReturn(true) - getNetworkCallback().onLost(NETWORK) + whenever(wifiManager.isWifiEnabled).thenReturn(true) + getNetworkCallback().onLost(NETWORK) - assertThat(underTest.isWifiEnabled.value).isTrue() + assertThat(underTest.isWifiEnabled.value).isTrue() - whenever(wifiManager.isWifiEnabled).thenReturn(false) - getNetworkCallback().onLost(NETWORK) + whenever(wifiManager.isWifiEnabled).thenReturn(false) + getNetworkCallback().onLost(NETWORK) - assertThat(underTest.isWifiEnabled.value).isFalse() + assertThat(underTest.isWifiEnabled.value).isFalse() - networkJob.cancel() - enabledJob.cancel() - } + networkJob.cancel() + enabledJob.cancel() + } @Test - fun isWifiEnabled_intentsReceived_valueUpdated() = runBlocking(IMMEDIATE) { - val intentFlow = MutableSharedFlow<Unit>() - whenever( - broadcastDispatcher.broadcastFlow( - any(), - nullable(), - anyInt(), - nullable(), - ) - ).thenReturn(intentFlow) - underTest = createRepo() + fun isWifiEnabled_intentsReceived_valueUpdated() = + runBlocking(IMMEDIATE) { + val intentFlow = MutableSharedFlow<Unit>() + whenever( + broadcastDispatcher.broadcastFlow( + any(), + nullable(), + anyInt(), + nullable(), + ) + ) + .thenReturn(intentFlow) + underTest = createRepo() - val job = underTest.isWifiEnabled.launchIn(this) + val job = underTest.isWifiEnabled.launchIn(this) - whenever(wifiManager.isWifiEnabled).thenReturn(true) - intentFlow.emit(Unit) + whenever(wifiManager.isWifiEnabled).thenReturn(true) + intentFlow.emit(Unit) - assertThat(underTest.isWifiEnabled.value).isTrue() + assertThat(underTest.isWifiEnabled.value).isTrue() - whenever(wifiManager.isWifiEnabled).thenReturn(false) - intentFlow.emit(Unit) + whenever(wifiManager.isWifiEnabled).thenReturn(false) + intentFlow.emit(Unit) - assertThat(underTest.isWifiEnabled.value).isFalse() + assertThat(underTest.isWifiEnabled.value).isFalse() - job.cancel() - } + job.cancel() + } @Test - fun isWifiEnabled_bothIntentAndNetworkUpdates_valueAlwaysUpdated() = runBlocking(IMMEDIATE) { - val intentFlow = MutableSharedFlow<Unit>() - whenever( - broadcastDispatcher.broadcastFlow( - any(), - nullable(), - anyInt(), - nullable(), - ) - ).thenReturn(intentFlow) - underTest = createRepo() - - val networkJob = underTest.wifiNetwork.launchIn(this) - val enabledJob = underTest.isWifiEnabled.launchIn(this) - - whenever(wifiManager.isWifiEnabled).thenReturn(false) - intentFlow.emit(Unit) - assertThat(underTest.isWifiEnabled.value).isFalse() - - whenever(wifiManager.isWifiEnabled).thenReturn(true) - getNetworkCallback().onLost(NETWORK) - assertThat(underTest.isWifiEnabled.value).isTrue() - - whenever(wifiManager.isWifiEnabled).thenReturn(false) - getNetworkCallback().onCapabilitiesChanged( - NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO) - ) - assertThat(underTest.isWifiEnabled.value).isFalse() + fun isWifiEnabled_bothIntentAndNetworkUpdates_valueAlwaysUpdated() = + runBlocking(IMMEDIATE) { + val intentFlow = MutableSharedFlow<Unit>() + whenever( + broadcastDispatcher.broadcastFlow( + any(), + nullable(), + anyInt(), + nullable(), + ) + ) + .thenReturn(intentFlow) + underTest = createRepo() + + val networkJob = underTest.wifiNetwork.launchIn(this) + val enabledJob = underTest.isWifiEnabled.launchIn(this) + + whenever(wifiManager.isWifiEnabled).thenReturn(false) + intentFlow.emit(Unit) + assertThat(underTest.isWifiEnabled.value).isFalse() + + whenever(wifiManager.isWifiEnabled).thenReturn(true) + getNetworkCallback().onLost(NETWORK) + assertThat(underTest.isWifiEnabled.value).isTrue() + + whenever(wifiManager.isWifiEnabled).thenReturn(false) + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)) + assertThat(underTest.isWifiEnabled.value).isFalse() - whenever(wifiManager.isWifiEnabled).thenReturn(true) - intentFlow.emit(Unit) - assertThat(underTest.isWifiEnabled.value).isTrue() + whenever(wifiManager.isWifiEnabled).thenReturn(true) + intentFlow.emit(Unit) + assertThat(underTest.isWifiEnabled.value).isTrue() - networkJob.cancel() - enabledJob.cancel() - } + networkJob.cancel() + enabledJob.cancel() + } @Test - fun isWifiDefault_initiallyGetsDefault() = runBlocking(IMMEDIATE) { - val job = underTest.isWifiDefault.launchIn(this) + fun isWifiDefault_initiallyGetsDefault() = + runBlocking(IMMEDIATE) { + val job = underTest.isWifiDefault.launchIn(this) - assertThat(underTest.isWifiDefault.value).isFalse() + assertThat(underTest.isWifiDefault.value).isFalse() - job.cancel() - } + job.cancel() + } @Test - fun isWifiDefault_wifiNetwork_isTrue() = runBlocking(IMMEDIATE) { - val job = underTest.isWifiDefault.launchIn(this) + fun isWifiDefault_wifiNetwork_isTrue() = + runBlocking(IMMEDIATE) { + val job = underTest.isWifiDefault.launchIn(this) - val wifiInfo = mock<WifiInfo>().apply { - whenever(this.ssid).thenReturn(SSID) - } + val wifiInfo = mock<WifiInfo>().apply { whenever(this.ssid).thenReturn(SSID) } - getDefaultNetworkCallback().onCapabilitiesChanged( - NETWORK, - createWifiNetworkCapabilities(wifiInfo) - ) + getDefaultNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo)) - assertThat(underTest.isWifiDefault.value).isTrue() + assertThat(underTest.isWifiDefault.value).isTrue() - job.cancel() - } + job.cancel() + } /** Regression test for b/266628069. */ @Test @@ -252,16 +255,18 @@ class WifiRepositoryImplTest : SysuiTestCase() { runBlocking(IMMEDIATE) { val job = underTest.isWifiDefault.launchIn(this) - val transportInfo = VpnTransportInfo( - /* type= */ 0, - /* sessionId= */ "sessionId", - ) - val networkCapabilities = mock<NetworkCapabilities>().also { - whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true) - whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) - whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) - whenever(it.transportInfo).thenReturn(transportInfo) - } + val transportInfo = + VpnTransportInfo( + /* type= */ 0, + /* sessionId= */ "sessionId", + ) + val networkCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true) + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false) + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) + whenever(it.transportInfo).thenReturn(transportInfo) + } getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, networkCapabilities) @@ -276,16 +281,18 @@ class WifiRepositoryImplTest : SysuiTestCase() { runBlocking(IMMEDIATE) { val job = underTest.isWifiDefault.launchIn(this) - val transportInfo = VpnTransportInfo( - /* type= */ 0, - /* sessionId= */ "sessionId", - ) - val networkCapabilities = mock<NetworkCapabilities>().also { - whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true) - whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) - whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) - whenever(it.transportInfo).thenReturn(transportInfo) - } + val transportInfo = + VpnTransportInfo( + /* type= */ 0, + /* sessionId= */ "sessionId", + ) + val networkCapabilities = + mock<NetworkCapabilities>().also { + whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true) + whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false) + whenever(it.transportInfo).thenReturn(transportInfo) + } getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, networkCapabilities) @@ -295,31 +302,34 @@ class WifiRepositoryImplTest : SysuiTestCase() { } @Test - fun isWifiDefault_cellularVcnNetwork_isTrue() = runBlocking(IMMEDIATE) { - val job = underTest.isWifiDefault.launchIn(this) + fun isWifiDefault_cellularVcnNetwork_isTrue() = + runBlocking(IMMEDIATE) { + val job = underTest.isWifiDefault.launchIn(this) - val capabilities = mock<NetworkCapabilities>().apply { - whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) - whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO)) - } + val capabilities = + mock<NetworkCapabilities>().apply { + whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO)) + } - getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) - assertThat(underTest.isWifiDefault.value).isTrue() + assertThat(underTest.isWifiDefault.value).isTrue() - job.cancel() - } + job.cancel() + } @Test fun wifiNetwork_cellularAndWifiTransports_usesCellular_isTrue() = runBlocking(IMMEDIATE) { val job = underTest.isWifiDefault.launchIn(this) - val capabilities = mock<NetworkCapabilities>().apply { - whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) - whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true) - whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO)) - } + val capabilities = + mock<NetworkCapabilities>().apply { + whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO)) + } getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) @@ -329,117 +339,115 @@ class WifiRepositoryImplTest : SysuiTestCase() { } @Test - fun isWifiDefault_cellularNotVcnNetwork_isFalse() = runBlocking(IMMEDIATE) { - val job = underTest.isWifiDefault.launchIn(this) + fun isWifiDefault_cellularNotVcnNetwork_isFalse() = + runBlocking(IMMEDIATE) { + val job = underTest.isWifiDefault.launchIn(this) - val capabilities = mock<NetworkCapabilities>().apply { - whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) - whenever(this.transportInfo).thenReturn(mock()) - } + val capabilities = + mock<NetworkCapabilities>().apply { + whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(this.transportInfo).thenReturn(mock()) + } - getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) + getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) - assertThat(underTest.isWifiDefault.value).isFalse() + assertThat(underTest.isWifiDefault.value).isFalse() - job.cancel() - } + job.cancel() + } @Test - fun isWifiDefault_wifiNetworkLost_isFalse() = runBlocking(IMMEDIATE) { - val job = underTest.isWifiDefault.launchIn(this) + fun isWifiDefault_wifiNetworkLost_isFalse() = + runBlocking(IMMEDIATE) { + val job = underTest.isWifiDefault.launchIn(this) - // First, add a network - getDefaultNetworkCallback() - .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)) - assertThat(underTest.isWifiDefault.value).isTrue() + // First, add a network + getDefaultNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)) + assertThat(underTest.isWifiDefault.value).isTrue() - // WHEN the network is lost - getDefaultNetworkCallback().onLost(NETWORK) + // WHEN the network is lost + getDefaultNetworkCallback().onLost(NETWORK) - // THEN we update to false - assertThat(underTest.isWifiDefault.value).isFalse() + // THEN we update to false + assertThat(underTest.isWifiDefault.value).isFalse() - job.cancel() - } + job.cancel() + } @Test - fun wifiNetwork_initiallyGetsDefault() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + fun wifiNetwork_initiallyGetsDefault() = + runBlocking(IMMEDIATE) { + var latest: WifiNetworkModel? = null + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) - assertThat(latest).isEqualTo(WIFI_NETWORK_DEFAULT) + assertThat(latest).isEqualTo(WIFI_NETWORK_DEFAULT) - job.cancel() - } + job.cancel() + } @Test - fun wifiNetwork_primaryWifiNetworkAdded_flowHasNetwork() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + 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) - } + 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)) + 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) + 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() - } + job.cancel() + } @Test - fun wifiNetwork_isCarrierMerged_flowHasCarrierMerged() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + fun wifiNetwork_isCarrierMerged_flowHasCarrierMerged() = + runBlocking(IMMEDIATE) { + var latest: WifiNetworkModel? = null + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) - val wifiInfo = mock<WifiInfo>().apply { - whenever(this.isPrimary).thenReturn(true) - whenever(this.isCarrierMerged).thenReturn(true) - } + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.isPrimary).thenReturn(true) + whenever(this.isCarrierMerged).thenReturn(true) + } - getNetworkCallback().onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo)) + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo)) - assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue() + assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue() - job.cancel() - } + job.cancel() + } @Test fun wifiNetwork_carrierMergedButInvalidSubId_flowHasInvalid() = runBlocking(IMMEDIATE) { var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) - val wifiInfo = mock<WifiInfo>().apply { - whenever(this.isPrimary).thenReturn(true) - whenever(this.isCarrierMerged).thenReturn(true) - whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID) - } + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.isPrimary).thenReturn(true) + whenever(this.isCarrierMerged).thenReturn(true) + whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID) + } - getNetworkCallback().onCapabilitiesChanged( - NETWORK, - createWifiNetworkCapabilities(wifiInfo), - ) + getNetworkCallback() + .onCapabilitiesChanged( + NETWORK, + createWifiNetworkCapabilities(wifiInfo), + ) assertThat(latest).isInstanceOf(WifiNetworkModel.Invalid::class.java) @@ -450,26 +458,25 @@ class WifiRepositoryImplTest : SysuiTestCase() { fun wifiNetwork_isCarrierMerged_getsCorrectValues() = runBlocking(IMMEDIATE) { var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) val rssi = -57 - val wifiInfo = mock<WifiInfo>().apply { - whenever(this.isPrimary).thenReturn(true) - whenever(this.isCarrierMerged).thenReturn(true) - whenever(this.rssi).thenReturn(rssi) - whenever(this.subscriptionId).thenReturn(567) - } + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.isPrimary).thenReturn(true) + whenever(this.isCarrierMerged).thenReturn(true) + whenever(this.rssi).thenReturn(rssi) + whenever(this.subscriptionId).thenReturn(567) + } whenever(wifiManager.calculateSignalLevel(rssi)).thenReturn(2) whenever(wifiManager.maxSignalLevel).thenReturn(5) - getNetworkCallback().onCapabilitiesChanged( - NETWORK, - createWifiNetworkCapabilities(wifiInfo), - ) + getNetworkCallback() + .onCapabilitiesChanged( + NETWORK, + createWifiNetworkCapabilities(wifiInfo), + ) assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue() val latestCarrierMerged = latest as WifiNetworkModel.CarrierMerged @@ -483,73 +490,71 @@ class WifiRepositoryImplTest : SysuiTestCase() { } @Test - fun wifiNetwork_notValidated_networkNotValidated() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + fun wifiNetwork_notValidated_networkNotValidated() = + runBlocking(IMMEDIATE) { + var latest: WifiNetworkModel? = null + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) - getNetworkCallback().onCapabilitiesChanged( - NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO, isValidated = false) - ) + getNetworkCallback() + .onCapabilitiesChanged( + NETWORK, + createWifiNetworkCapabilities(PRIMARY_WIFI_INFO, isValidated = false) + ) - assertThat((latest as WifiNetworkModel.Active).isValidated).isFalse() + assertThat((latest as WifiNetworkModel.Active).isValidated).isFalse() - job.cancel() - } + job.cancel() + } @Test - fun wifiNetwork_validated_networkValidated() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + fun wifiNetwork_validated_networkValidated() = + runBlocking(IMMEDIATE) { + var latest: WifiNetworkModel? = null + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) - getNetworkCallback().onCapabilitiesChanged( - NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO, isValidated = true) - ) + getNetworkCallback() + .onCapabilitiesChanged( + NETWORK, + createWifiNetworkCapabilities(PRIMARY_WIFI_INFO, isValidated = true) + ) - assertThat((latest as WifiNetworkModel.Active).isValidated).isTrue() + assertThat((latest as WifiNetworkModel.Active).isValidated).isTrue() - job.cancel() - } + job.cancel() + } @Test - fun wifiNetwork_nonPrimaryWifiNetworkAdded_flowHasNoNetwork() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + 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) - } + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.ssid).thenReturn(SSID) + whenever(this.isPrimary).thenReturn(false) + } - getNetworkCallback().onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo)) + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(wifiInfo)) - assertThat(latest is WifiNetworkModel.Inactive).isTrue() + assertThat(latest is WifiNetworkModel.Inactive).isTrue() - job.cancel() - } + job.cancel() + } /** Regression test for b/266628069. */ @Test fun wifiNetwork_transportInfoIsNotWifi_flowHasNoNetwork() = runBlocking(IMMEDIATE) { var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) - - val transportInfo = VpnTransportInfo( - /* type= */ 0, - /* sessionId= */ "sessionId", - ) + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) + + val transportInfo = + VpnTransportInfo( + /* type= */ 0, + /* sessionId= */ "sessionId", + ) getNetworkCallback() .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(transportInfo)) @@ -559,86 +564,82 @@ class WifiRepositoryImplTest : SysuiTestCase() { } @Test - fun wifiNetwork_cellularVcnNetworkAdded_flowHasNetwork() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + 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)) - } + val capabilities = + mock<NetworkCapabilities>().apply { + whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO)) + } - getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) + 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) + 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() - } + 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)) - } + 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) + getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) - assertThat(latest is WifiNetworkModel.Inactive).isTrue() + assertThat(latest is WifiNetworkModel.Inactive).isTrue() - job.cancel() - } + job.cancel() + } @Test - fun wifiNetwork_cellularNotVcnNetworkAdded_flowHasNoNetwork() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + 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()) - } + val capabilities = + mock<NetworkCapabilities>().apply { + whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(this.transportInfo).thenReturn(mock()) + } - getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) + getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) - assertThat(latest is WifiNetworkModel.Inactive).isTrue() + assertThat(latest is WifiNetworkModel.Inactive).isTrue() - job.cancel() - } + job.cancel() + } @Test fun wifiNetwork_cellularAndWifiTransports_usesCellular() = 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.hasTransport(TRANSPORT_WIFI)).thenReturn(true) - whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO)) - } + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) + + val capabilities = + mock<NetworkCapabilities>().apply { + whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true) + whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true) + whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO)) + } getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities) @@ -651,309 +652,280 @@ class WifiRepositoryImplTest : SysuiTestCase() { } @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)) + fun wifiNetwork_newPrimaryWifiNetwork_flowHasNewNetwork() = + runBlocking(IMMEDIATE) { + var latest: WifiNetworkModel? = null + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) - // 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) - } + // 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) - ) + 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) + // 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() - } + 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)) + fun wifiNetwork_newNonPrimaryWifiNetwork_flowHasOldNetwork() = + runBlocking(IMMEDIATE) { + var latest: WifiNetworkModel? = null + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) - // 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) - } + // 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) - ) + 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) + // 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() - } + 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) - } + fun wifiNetwork_newNetworkCapabilities_flowHasNewData() = + runBlocking(IMMEDIATE) { + var latest: WifiNetworkModel? = null + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) - // Start with the original network - getNetworkCallback().onCapabilitiesChanged( - NETWORK, createWifiNetworkCapabilities(wifiInfo, isValidated = true) - ) + val wifiInfo = + mock<WifiInfo>().apply { + whenever(this.ssid).thenReturn(SSID) + whenever(this.isPrimary).thenReturn(true) + } - // 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) - } + // Start with the original network + getNetworkCallback() + .onCapabilitiesChanged( + NETWORK, + createWifiNetworkCapabilities(wifiInfo, isValidated = true) + ) + + // 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, isValidated = false) - ) + getNetworkCallback() + .onCapabilitiesChanged( + NETWORK, + createWifiNetworkCapabilities(newWifiInfo, isValidated = false) + ) - // 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) - assertThat(latestActive.isValidated).isFalse() + // 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) + assertThat(latestActive.isValidated).isFalse() - job.cancel() - } + job.cancel() + } @Test - fun wifiNetwork_noCurrentNetwork_networkLost_flowHasNoNetwork() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + 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) + // 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() + // THEN there's no crash and we still have no network + assertThat(latest is WifiNetworkModel.Inactive).isTrue() - job.cancel() - } + job.cancel() + } @Test - fun wifiNetwork_currentNetworkLost_flowHasNoNetwork() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + 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) + 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) + // WHEN we lose our current network + getNetworkCallback().onLost(NETWORK) - // THEN we update to no network - assertThat(latest is WifiNetworkModel.Inactive).isTrue() + // THEN we update to no network + assertThat(latest is WifiNetworkModel.Inactive).isTrue() - job.cancel() - } + job.cancel() + } @Test - fun wifiNetwork_unknownNetworkLost_flowHasPreviousNetwork() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + 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) + 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) + // 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) + // 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() - } + job.cancel() + } @Test - fun wifiNetwork_notCurrentNetworkLost_flowHasCurrentNetwork() = runBlocking(IMMEDIATE) { - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) + 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) + 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) + // 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) + // THEN we still have the new network + assertThat((latest as WifiNetworkModel.Active).networkId).isEqualTo(newNetworkId) - job.cancel() - } + job.cancel() + } /** Regression test for b/244173280. */ @Test - fun wifiNetwork_multipleSubscribers_newSubscribersGetCurrentValue() = runBlocking(IMMEDIATE) { - var latest1: WifiNetworkModel? = null - val job1 = underTest - .wifiNetwork - .onEach { latest1 = it } - .launchIn(this) - - getNetworkCallback() - .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)) - - assertThat(latest1 is WifiNetworkModel.Active).isTrue() - val latest1Active = latest1 as WifiNetworkModel.Active - assertThat(latest1Active.networkId).isEqualTo(NETWORK_ID) - assertThat(latest1Active.ssid).isEqualTo(SSID) - - // WHEN we add a second subscriber after having already emitted a value - var latest2: WifiNetworkModel? = null - val job2 = underTest - .wifiNetwork - .onEach { latest2 = it } - .launchIn(this) - - // THEN the second subscribe receives the already-emitted value - assertThat(latest2 is WifiNetworkModel.Active).isTrue() - val latest2Active = latest2 as WifiNetworkModel.Active - assertThat(latest2Active.networkId).isEqualTo(NETWORK_ID) - assertThat(latest2Active.ssid).isEqualTo(SSID) - - job1.cancel() - job2.cancel() - } + fun wifiNetwork_multipleSubscribers_newSubscribersGetCurrentValue() = + runBlocking(IMMEDIATE) { + var latest1: WifiNetworkModel? = null + val job1 = underTest.wifiNetwork.onEach { latest1 = it }.launchIn(this) + + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)) + + assertThat(latest1 is WifiNetworkModel.Active).isTrue() + val latest1Active = latest1 as WifiNetworkModel.Active + assertThat(latest1Active.networkId).isEqualTo(NETWORK_ID) + assertThat(latest1Active.ssid).isEqualTo(SSID) + + // WHEN we add a second subscriber after having already emitted a value + var latest2: WifiNetworkModel? = null + val job2 = underTest.wifiNetwork.onEach { latest2 = it }.launchIn(this) + + // THEN the second subscribe receives the already-emitted value + assertThat(latest2 is WifiNetworkModel.Active).isTrue() + val latest2Active = latest2 as WifiNetworkModel.Active + assertThat(latest2Active.networkId).isEqualTo(NETWORK_ID) + assertThat(latest2Active.ssid).isEqualTo(SSID) + + job1.cancel() + job2.cancel() + } @Test - fun wifiActivity_callbackGivesNone_activityFlowHasNone() = runBlocking(IMMEDIATE) { - var latest: DataActivityModel? = null - val job = underTest - .wifiActivity - .onEach { latest = it } - .launchIn(this) + fun wifiActivity_callbackGivesNone_activityFlowHasNone() = + runBlocking(IMMEDIATE) { + var latest: DataActivityModel? = null + val job = underTest.wifiActivity.onEach { latest = it }.launchIn(this) - getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_NONE) + getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_NONE) - assertThat(latest).isEqualTo( - DataActivityModel(hasActivityIn = false, hasActivityOut = false) - ) + assertThat(latest) + .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false)) - job.cancel() - } + job.cancel() + } @Test - fun wifiActivity_callbackGivesIn_activityFlowHasIn() = runBlocking(IMMEDIATE) { - var latest: DataActivityModel? = null - val job = underTest - .wifiActivity - .onEach { latest = it } - .launchIn(this) + fun wifiActivity_callbackGivesIn_activityFlowHasIn() = + runBlocking(IMMEDIATE) { + var latest: DataActivityModel? = null + val job = underTest.wifiActivity.onEach { latest = it }.launchIn(this) - getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_IN) + getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_IN) - assertThat(latest).isEqualTo( - DataActivityModel(hasActivityIn = true, hasActivityOut = false) - ) + assertThat(latest) + .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = false)) - job.cancel() - } + job.cancel() + } @Test - fun wifiActivity_callbackGivesOut_activityFlowHasOut() = runBlocking(IMMEDIATE) { - var latest: DataActivityModel? = null - val job = underTest - .wifiActivity - .onEach { latest = it } - .launchIn(this) + fun wifiActivity_callbackGivesOut_activityFlowHasOut() = + runBlocking(IMMEDIATE) { + var latest: DataActivityModel? = null + val job = underTest.wifiActivity.onEach { latest = it }.launchIn(this) - getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_OUT) + getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_OUT) - assertThat(latest).isEqualTo( - DataActivityModel(hasActivityIn = false, hasActivityOut = true) - ) + assertThat(latest) + .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = true)) - job.cancel() - } + job.cancel() + } @Test - fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() = runBlocking(IMMEDIATE) { - var latest: DataActivityModel? = null - val job = underTest - .wifiActivity - .onEach { latest = it } - .launchIn(this) + fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() = + runBlocking(IMMEDIATE) { + var latest: DataActivityModel? = null + val job = underTest.wifiActivity.onEach { latest = it }.launchIn(this) - getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_INOUT) + getTrafficStateCallback().onStateChanged(TrafficStateCallback.DATA_ACTIVITY_INOUT) - assertThat(latest).isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true)) + assertThat(latest) + .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true)) - job.cancel() - } + job.cancel() + } private fun createRepo(): WifiRepositoryImpl { return WifiRepositoryImpl( @@ -998,14 +970,13 @@ class WifiRepositoryImplTest : SysuiTestCase() { private companion object { const val NETWORK_ID = 45 - val NETWORK = mock<Network>().apply { - whenever(this.getNetId()).thenReturn(NETWORK_ID) - } + 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) - } + val PRIMARY_WIFI_INFO: WifiInfo = + mock<WifiInfo>().apply { + whenever(this.ssid).thenReturn(SSID) + whenever(this.isPrimary).thenReturn(true) + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt index 089a170aa2be..fc2277b9c803 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt @@ -22,8 +22,8 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository -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.shared.model.WifiNetworkModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -57,10 +57,7 @@ class WifiInteractorImplTest : SysuiTestCase() { wifiRepository.setWifiNetwork(WifiNetworkModel.Unavailable) var latest: String? = "default" - val job = underTest - .ssid - .onEach { latest = it } - .launchIn(this) + val job = underTest.ssid.onEach { latest = it }.launchIn(this) assertThat(latest).isNull() @@ -68,238 +65,223 @@ class WifiInteractorImplTest : SysuiTestCase() { } @Test - fun ssid_inactiveNetwork_outputsNull() = runBlocking(IMMEDIATE) { - wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive) + fun ssid_inactiveNetwork_outputsNull() = + runBlocking(IMMEDIATE) { + wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive) - var latest: String? = "default" - val job = underTest - .ssid - .onEach { latest = it } - .launchIn(this) + var latest: String? = "default" + val job = underTest.ssid.onEach { latest = it }.launchIn(this) - assertThat(latest).isNull() + assertThat(latest).isNull() - job.cancel() - } + job.cancel() + } @Test - fun ssid_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) { - wifiRepository.setWifiNetwork( - WifiNetworkModel.CarrierMerged(networkId = 1, subscriptionId = 2, level = 1) - ) + fun ssid_carrierMergedNetwork_outputsNull() = + runBlocking(IMMEDIATE) { + wifiRepository.setWifiNetwork( + WifiNetworkModel.CarrierMerged(networkId = 1, subscriptionId = 2, level = 1) + ) - var latest: String? = "default" - val job = underTest - .ssid - .onEach { latest = it } - .launchIn(this) + var latest: String? = "default" + val job = underTest.ssid.onEach { latest = it }.launchIn(this) - assertThat(latest).isNull() + assertThat(latest).isNull() - job.cancel() - } + job.cancel() + } @Test - fun ssid_isPasspointAccessPoint_outputsPasspointName() = runBlocking(IMMEDIATE) { - wifiRepository.setWifiNetwork(WifiNetworkModel.Active( - networkId = 1, - level = 1, - isPasspointAccessPoint = true, - passpointProviderFriendlyName = "friendly", - )) - - var latest: String? = null - val job = underTest - .ssid - .onEach { latest = it } - .launchIn(this) - - assertThat(latest).isEqualTo("friendly") - - job.cancel() - } + fun ssid_isPasspointAccessPoint_outputsPasspointName() = + runBlocking(IMMEDIATE) { + wifiRepository.setWifiNetwork( + WifiNetworkModel.Active( + networkId = 1, + level = 1, + isPasspointAccessPoint = true, + passpointProviderFriendlyName = "friendly", + ) + ) + + var latest: String? = null + val job = underTest.ssid.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo("friendly") + + job.cancel() + } @Test - fun ssid_isOnlineSignUpForPasspoint_outputsPasspointName() = runBlocking(IMMEDIATE) { - wifiRepository.setWifiNetwork(WifiNetworkModel.Active( - networkId = 1, - level = 1, - isOnlineSignUpForPasspointAccessPoint = true, - passpointProviderFriendlyName = "friendly", - )) - - var latest: String? = null - val job = underTest - .ssid - .onEach { latest = it } - .launchIn(this) - - assertThat(latest).isEqualTo("friendly") - - job.cancel() - } + fun ssid_isOnlineSignUpForPasspoint_outputsPasspointName() = + runBlocking(IMMEDIATE) { + wifiRepository.setWifiNetwork( + WifiNetworkModel.Active( + networkId = 1, + level = 1, + isOnlineSignUpForPasspointAccessPoint = true, + passpointProviderFriendlyName = "friendly", + ) + ) + + var latest: String? = null + val job = underTest.ssid.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo("friendly") + + job.cancel() + } @Test - fun ssid_unknownSsid_outputsNull() = runBlocking(IMMEDIATE) { - wifiRepository.setWifiNetwork(WifiNetworkModel.Active( - networkId = 1, - level = 1, - ssid = WifiManager.UNKNOWN_SSID, - )) - - var latest: String? = "default" - val job = underTest - .ssid - .onEach { latest = it } - .launchIn(this) - - assertThat(latest).isNull() - - job.cancel() - } + fun ssid_unknownSsid_outputsNull() = + runBlocking(IMMEDIATE) { + wifiRepository.setWifiNetwork( + WifiNetworkModel.Active( + networkId = 1, + level = 1, + ssid = WifiManager.UNKNOWN_SSID, + ) + ) + + var latest: String? = "default" + val job = underTest.ssid.onEach { latest = it }.launchIn(this) + + assertThat(latest).isNull() + + job.cancel() + } @Test - fun ssid_validSsid_outputsSsid() = runBlocking(IMMEDIATE) { - wifiRepository.setWifiNetwork(WifiNetworkModel.Active( - networkId = 1, - level = 1, - ssid = "MyAwesomeWifiNetwork", - )) - - var latest: String? = null - val job = underTest - .ssid - .onEach { latest = it } - .launchIn(this) - - assertThat(latest).isEqualTo("MyAwesomeWifiNetwork") - - job.cancel() - } + fun ssid_validSsid_outputsSsid() = + runBlocking(IMMEDIATE) { + wifiRepository.setWifiNetwork( + WifiNetworkModel.Active( + networkId = 1, + level = 1, + ssid = "MyAwesomeWifiNetwork", + ) + ) + + var latest: String? = null + val job = underTest.ssid.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo("MyAwesomeWifiNetwork") + + job.cancel() + } @Test - fun isEnabled_matchesRepoIsEnabled() = runBlocking(IMMEDIATE) { - var latest: Boolean? = null - val job = underTest - .isEnabled - .onEach { latest = it } - .launchIn(this) - - wifiRepository.setIsWifiEnabled(true) - yield() - assertThat(latest).isTrue() - - wifiRepository.setIsWifiEnabled(false) - yield() - assertThat(latest).isFalse() - - wifiRepository.setIsWifiEnabled(true) - yield() - assertThat(latest).isTrue() - - job.cancel() - } + fun isEnabled_matchesRepoIsEnabled() = + runBlocking(IMMEDIATE) { + var latest: Boolean? = null + val job = underTest.isEnabled.onEach { latest = it }.launchIn(this) + + wifiRepository.setIsWifiEnabled(true) + yield() + assertThat(latest).isTrue() + + wifiRepository.setIsWifiEnabled(false) + yield() + assertThat(latest).isFalse() + + wifiRepository.setIsWifiEnabled(true) + yield() + assertThat(latest).isTrue() + + job.cancel() + } @Test - fun isDefault_matchesRepoIsDefault() = runBlocking(IMMEDIATE) { - var latest: Boolean? = null - val job = underTest - .isDefault - .onEach { latest = it } - .launchIn(this) - - wifiRepository.setIsWifiDefault(true) - yield() - assertThat(latest).isTrue() - - wifiRepository.setIsWifiDefault(false) - yield() - assertThat(latest).isFalse() - - wifiRepository.setIsWifiDefault(true) - yield() - assertThat(latest).isTrue() - - job.cancel() - } + fun isDefault_matchesRepoIsDefault() = + runBlocking(IMMEDIATE) { + var latest: Boolean? = null + val job = underTest.isDefault.onEach { latest = it }.launchIn(this) + + wifiRepository.setIsWifiDefault(true) + yield() + assertThat(latest).isTrue() + + wifiRepository.setIsWifiDefault(false) + yield() + assertThat(latest).isFalse() + + wifiRepository.setIsWifiDefault(true) + yield() + assertThat(latest).isTrue() + + job.cancel() + } @Test - fun wifiNetwork_matchesRepoWifiNetwork() = runBlocking(IMMEDIATE) { - val wifiNetwork = WifiNetworkModel.Active( - networkId = 45, - isValidated = true, - level = 3, - ssid = "AB", - passpointProviderFriendlyName = "friendly" - ) - wifiRepository.setWifiNetwork(wifiNetwork) - - var latest: WifiNetworkModel? = null - val job = underTest - .wifiNetwork - .onEach { latest = it } - .launchIn(this) - - assertThat(latest).isEqualTo(wifiNetwork) - - job.cancel() - } + fun wifiNetwork_matchesRepoWifiNetwork() = + runBlocking(IMMEDIATE) { + val wifiNetwork = + WifiNetworkModel.Active( + networkId = 45, + isValidated = true, + level = 3, + ssid = "AB", + passpointProviderFriendlyName = "friendly" + ) + wifiRepository.setWifiNetwork(wifiNetwork) + + var latest: WifiNetworkModel? = null + val job = underTest.wifiNetwork.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo(wifiNetwork) + + job.cancel() + } @Test - fun activity_matchesRepoWifiActivity() = runBlocking(IMMEDIATE) { - var latest: DataActivityModel? = null - val job = underTest - .activity - .onEach { latest = it } - .launchIn(this) - - val activity1 = DataActivityModel(hasActivityIn = true, hasActivityOut = true) - wifiRepository.setWifiActivity(activity1) - yield() - assertThat(latest).isEqualTo(activity1) - - val activity2 = DataActivityModel(hasActivityIn = false, hasActivityOut = false) - wifiRepository.setWifiActivity(activity2) - yield() - assertThat(latest).isEqualTo(activity2) - - val activity3 = DataActivityModel(hasActivityIn = true, hasActivityOut = false) - wifiRepository.setWifiActivity(activity3) - yield() - assertThat(latest).isEqualTo(activity3) - - job.cancel() - } + fun activity_matchesRepoWifiActivity() = + runBlocking(IMMEDIATE) { + var latest: DataActivityModel? = null + val job = underTest.activity.onEach { latest = it }.launchIn(this) + + val activity1 = DataActivityModel(hasActivityIn = true, hasActivityOut = true) + wifiRepository.setWifiActivity(activity1) + yield() + assertThat(latest).isEqualTo(activity1) + + val activity2 = DataActivityModel(hasActivityIn = false, hasActivityOut = false) + wifiRepository.setWifiActivity(activity2) + yield() + assertThat(latest).isEqualTo(activity2) + + val activity3 = DataActivityModel(hasActivityIn = true, hasActivityOut = false) + wifiRepository.setWifiActivity(activity3) + yield() + assertThat(latest).isEqualTo(activity3) + + job.cancel() + } @Test - fun isForceHidden_repoHasWifiHidden_outputsTrue() = runBlocking(IMMEDIATE) { - connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI)) + fun isForceHidden_repoHasWifiHidden_outputsTrue() = + runBlocking(IMMEDIATE) { + connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI)) - var latest: Boolean? = null - val job = underTest - .isForceHidden - .onEach { latest = it } - .launchIn(this) + var latest: Boolean? = null + val job = underTest.isForceHidden.onEach { latest = it }.launchIn(this) - assertThat(latest).isTrue() + assertThat(latest).isTrue() - job.cancel() - } + job.cancel() + } @Test - fun isForceHidden_repoDoesNotHaveWifiHidden_outputsFalse() = runBlocking(IMMEDIATE) { - connectivityRepository.setForceHiddenIcons(setOf()) + fun isForceHidden_repoDoesNotHaveWifiHidden_outputsFalse() = + runBlocking(IMMEDIATE) { + connectivityRepository.setForceHiddenIcons(setOf()) - var latest: Boolean? = null - val job = underTest - .isForceHidden - .onEach { latest = it } - .launchIn(this) + var latest: Boolean? = null + val job = underTest.isForceHidden.onEach { latest = it }.launchIn(this) - assertThat(latest).isFalse() + assertThat(latest).isFalse() - job.cancel() - } + job.cancel() + } } private val IMMEDIATE = Dispatchers.Main.immediate diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt index 824cebdc3c08..ab4e93ceee84 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt @@ -14,14 +14,14 @@ * limitations under the License. */ -package com.android.systemui.statusbar.pipeline.wifi.data.model +package com.android.systemui.statusbar.pipeline.wifi.shared.model import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.log.table.TableRowLogger -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Active.Companion.MAX_VALID_LEVEL -import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Companion.MIN_VALID_LEVEL +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel.Active.Companion.MAX_VALID_LEVEL +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel.Companion.MIN_VALID_LEVEL import com.google.common.truth.Truth.assertThat import org.junit.Test 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 index b8ace2f04a61..60f564e5f2dc 100644 --- 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 @@ -38,11 +38,11 @@ import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneMod import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository -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.domain.interactor.WifiInteractorImpl import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel import com.android.systemui.util.mockito.whenever @@ -62,16 +62,11 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { private lateinit var testableLooper: TestableLooper - @Mock - private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags - @Mock - private lateinit var logger: ConnectivityPipelineLogger - @Mock - private lateinit var tableLogBuffer: TableLogBuffer - @Mock - private lateinit var connectivityConstants: ConnectivityConstants - @Mock - private lateinit var wifiConstants: WifiConstants + @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags + @Mock private lateinit var logger: ConnectivityPipelineLogger + @Mock private lateinit var tableLogBuffer: TableLogBuffer + @Mock private lateinit var connectivityConstants: ConnectivityConstants + @Mock private lateinit var wifiConstants: WifiConstants private lateinit var airplaneModeRepository: FakeAirplaneModeRepository private lateinit var connectivityRepository: FakeConnectivityRepository private lateinit var wifiRepository: FakeWifiRepository @@ -91,25 +86,28 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { wifiRepository.setIsWifiEnabled(true) interactor = WifiInteractorImpl(connectivityRepository, wifiRepository) scope = CoroutineScope(Dispatchers.Unconfined) - airplaneModeViewModel = AirplaneModeViewModelImpl( - AirplaneModeInteractor( - airplaneModeRepository, - connectivityRepository, - ), - logger, - scope, - ) - viewModel = WifiViewModel( - airplaneModeViewModel, - connectivityConstants, - context, - logger, - tableLogBuffer, - interactor, - scope, - statusBarPipelineFlags, - wifiConstants, - ).home + airplaneModeViewModel = + AirplaneModeViewModelImpl( + AirplaneModeInteractor( + airplaneModeRepository, + connectivityRepository, + ), + logger, + scope, + ) + viewModel = + WifiViewModel( + airplaneModeViewModel, + connectivityConstants, + context, + logger, + tableLogBuffer, + interactor, + scope, + statusBarPipelineFlags, + wifiConstants, + ) + .home } // Note: The following tests are more like integration tests, since they stand up a full diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt index b9328377772a..648d7a5f0f55 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt @@ -36,11 +36,11 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository -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.domain.interactor.WifiInteractorImpl import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel.Companion.NO_INTERNET import com.google.common.truth.Truth.assertThat 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 index e5cfec9c08c0..45ebb3903332 100644 --- 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 @@ -29,11 +29,11 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository -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.domain.interactor.WifiInteractorImpl import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants +import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope @@ -79,14 +79,15 @@ class WifiViewModelTest : SysuiTestCase() { wifiRepository.setIsWifiEnabled(true) interactor = WifiInteractorImpl(connectivityRepository, wifiRepository) scope = CoroutineScope(IMMEDIATE) - airplaneModeViewModel = AirplaneModeViewModelImpl( - AirplaneModeInteractor( - airplaneModeRepository, - connectivityRepository, - ), - logger, - scope, - ) + airplaneModeViewModel = + AirplaneModeViewModelImpl( + AirplaneModeInteractor( + airplaneModeRepository, + connectivityRepository, + ), + logger, + scope, + ) createAndSetViewModel() } @@ -104,451 +105,386 @@ class WifiViewModelTest : SysuiTestCase() { // instances. There are also some tests that verify all 3 instances received the same data. @Test - fun wifiIcon_allLocationViewModelsReceiveSameData() = runBlocking(IMMEDIATE) { - var latestHome: WifiIcon? = null - val jobHome = underTest - .home - .wifiIcon - .onEach { latestHome = it } - .launchIn(this) - - var latestKeyguard: WifiIcon? = null - val jobKeyguard = underTest - .keyguard - .wifiIcon - .onEach { latestKeyguard = it } - .launchIn(this) - - var latestQs: WifiIcon? = null - val jobQs = underTest - .qs - .wifiIcon - .onEach { latestQs = it } - .launchIn(this) - - wifiRepository.setWifiNetwork( - WifiNetworkModel.Active( - NETWORK_ID, - isValidated = true, - level = 1 + fun wifiIcon_allLocationViewModelsReceiveSameData() = + runBlocking(IMMEDIATE) { + var latestHome: WifiIcon? = null + val jobHome = underTest.home.wifiIcon.onEach { latestHome = it }.launchIn(this) + + var latestKeyguard: WifiIcon? = null + val jobKeyguard = + underTest.keyguard.wifiIcon.onEach { latestKeyguard = it }.launchIn(this) + + var latestQs: WifiIcon? = null + val jobQs = underTest.qs.wifiIcon.onEach { latestQs = it }.launchIn(this) + + wifiRepository.setWifiNetwork( + WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 1) ) - ) - yield() + yield() - assertThat(latestHome).isInstanceOf(WifiIcon.Visible::class.java) - assertThat(latestHome).isEqualTo(latestKeyguard) - assertThat(latestKeyguard).isEqualTo(latestQs) + assertThat(latestHome).isInstanceOf(WifiIcon.Visible::class.java) + assertThat(latestHome).isEqualTo(latestKeyguard) + assertThat(latestKeyguard).isEqualTo(latestQs) - jobHome.cancel() - jobKeyguard.cancel() - jobQs.cancel() - } + jobHome.cancel() + jobKeyguard.cancel() + jobQs.cancel() + } @Test - fun activity_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(false) - createAndSetViewModel() - wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) - - var activityIn: Boolean? = null - val activityInJob = underTest - .home - .isActivityInViewVisible - .onEach { activityIn = it } - .launchIn(this) - - var activityOut: Boolean? = null - val activityOutJob = underTest - .home - .isActivityOutViewVisible - .onEach { activityOut = it } - .launchIn(this) - - var activityContainer: Boolean? = null - val activityContainerJob = underTest - .home - .isActivityContainerVisible - .onEach { activityContainer = it } - .launchIn(this) - - // Verify that on launch, we receive false. - assertThat(activityIn).isFalse() - assertThat(activityOut).isFalse() - assertThat(activityContainer).isFalse() - - activityInJob.cancel() - activityOutJob.cancel() - activityContainerJob.cancel() - } + fun activity_showActivityConfigFalse_outputsFalse() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(false) + createAndSetViewModel() + wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) + + var activityIn: Boolean? = null + val activityInJob = + underTest.home.isActivityInViewVisible.onEach { activityIn = it }.launchIn(this) + + var activityOut: Boolean? = null + val activityOutJob = + underTest.home.isActivityOutViewVisible.onEach { activityOut = it }.launchIn(this) + + var activityContainer: Boolean? = null + val activityContainerJob = + underTest.home.isActivityContainerVisible + .onEach { activityContainer = it } + .launchIn(this) + + // Verify that on launch, we receive false. + assertThat(activityIn).isFalse() + assertThat(activityOut).isFalse() + assertThat(activityContainer).isFalse() + + activityInJob.cancel() + activityOutJob.cancel() + activityContainerJob.cancel() + } @Test - fun activity_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(false) - createAndSetViewModel() - wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) - - var activityIn: Boolean? = null - val activityInJob = underTest - .home - .isActivityInViewVisible - .onEach { activityIn = it } - .launchIn(this) - - var activityOut: Boolean? = null - val activityOutJob = underTest - .home - .isActivityOutViewVisible - .onEach { activityOut = it } - .launchIn(this) - - var activityContainer: Boolean? = null - val activityContainerJob = underTest - .home - .isActivityContainerVisible - .onEach { activityContainer = it } - .launchIn(this) - - // WHEN we update the repo to have activity - val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) - wifiRepository.setWifiActivity(activity) - yield() - - // THEN we didn't update to the new activity (because our config is false) - assertThat(activityIn).isFalse() - assertThat(activityOut).isFalse() - assertThat(activityContainer).isFalse() - - activityInJob.cancel() - activityOutJob.cancel() - activityContainerJob.cancel() - } + fun activity_showActivityConfigFalse_noUpdatesReceived() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(false) + createAndSetViewModel() + wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) + + var activityIn: Boolean? = null + val activityInJob = + underTest.home.isActivityInViewVisible.onEach { activityIn = it }.launchIn(this) + + var activityOut: Boolean? = null + val activityOutJob = + underTest.home.isActivityOutViewVisible.onEach { activityOut = it }.launchIn(this) + + var activityContainer: Boolean? = null + val activityContainerJob = + underTest.home.isActivityContainerVisible + .onEach { activityContainer = it } + .launchIn(this) + + // WHEN we update the repo to have activity + val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) + wifiRepository.setWifiActivity(activity) + yield() + + // THEN we didn't update to the new activity (because our config is false) + assertThat(activityIn).isFalse() + assertThat(activityOut).isFalse() + assertThat(activityContainer).isFalse() + + activityInJob.cancel() + activityOutJob.cancel() + activityContainerJob.cancel() + } @Test - fun activity_nullSsid_outputsFalse() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) - createAndSetViewModel() + fun activity_nullSsid_outputsFalse() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) + createAndSetViewModel() - wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, ssid = null, level = 1)) - - var activityIn: Boolean? = null - val activityInJob = underTest - .home - .isActivityInViewVisible - .onEach { activityIn = it } - .launchIn(this) - - var activityOut: Boolean? = null - val activityOutJob = underTest - .home - .isActivityOutViewVisible - .onEach { activityOut = it } - .launchIn(this) - - var activityContainer: Boolean? = null - val activityContainerJob = underTest - .home - .isActivityContainerVisible - .onEach { activityContainer = it } - .launchIn(this) - - // WHEN we update the repo to have activity - val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) - wifiRepository.setWifiActivity(activity) - yield() - - // THEN we still output false because our network's SSID is null - assertThat(activityIn).isFalse() - assertThat(activityOut).isFalse() - assertThat(activityContainer).isFalse() - - activityInJob.cancel() - activityOutJob.cancel() - activityContainerJob.cancel() - } + wifiRepository.setWifiNetwork( + WifiNetworkModel.Active(NETWORK_ID, ssid = null, level = 1) + ) + + var activityIn: Boolean? = null + val activityInJob = + underTest.home.isActivityInViewVisible.onEach { activityIn = it }.launchIn(this) + + var activityOut: Boolean? = null + val activityOutJob = + underTest.home.isActivityOutViewVisible.onEach { activityOut = it }.launchIn(this) + + var activityContainer: Boolean? = null + val activityContainerJob = + underTest.home.isActivityContainerVisible + .onEach { activityContainer = it } + .launchIn(this) + + // WHEN we update the repo to have activity + val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) + wifiRepository.setWifiActivity(activity) + yield() + + // THEN we still output false because our network's SSID is null + assertThat(activityIn).isFalse() + assertThat(activityOut).isFalse() + assertThat(activityContainer).isFalse() + + activityInJob.cancel() + activityOutJob.cancel() + activityContainerJob.cancel() + } @Test - fun activity_allLocationViewModelsReceiveSameData() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) - createAndSetViewModel() - wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) - - var latestHome: Boolean? = null - val jobHome = underTest - .home - .isActivityInViewVisible - .onEach { latestHome = it } - .launchIn(this) - - var latestKeyguard: Boolean? = null - val jobKeyguard = underTest - .keyguard - .isActivityInViewVisible - .onEach { latestKeyguard = it } - .launchIn(this) - - var latestQs: Boolean? = null - val jobQs = underTest - .qs - .isActivityInViewVisible - .onEach { latestQs = it } - .launchIn(this) - - val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) - wifiRepository.setWifiActivity(activity) - yield() - - assertThat(latestHome).isTrue() - assertThat(latestKeyguard).isTrue() - assertThat(latestQs).isTrue() - - jobHome.cancel() - jobKeyguard.cancel() - jobQs.cancel() - } + fun activity_allLocationViewModelsReceiveSameData() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) + createAndSetViewModel() + wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) + + var latestHome: Boolean? = null + val jobHome = + underTest.home.isActivityInViewVisible.onEach { latestHome = it }.launchIn(this) + + var latestKeyguard: Boolean? = null + val jobKeyguard = + underTest.keyguard.isActivityInViewVisible + .onEach { latestKeyguard = it } + .launchIn(this) + + var latestQs: Boolean? = null + val jobQs = underTest.qs.isActivityInViewVisible.onEach { latestQs = it }.launchIn(this) + + val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) + wifiRepository.setWifiActivity(activity) + yield() + + assertThat(latestHome).isTrue() + assertThat(latestKeyguard).isTrue() + assertThat(latestQs).isTrue() + + jobHome.cancel() + jobKeyguard.cancel() + jobQs.cancel() + } @Test - fun activityIn_hasActivityInTrue_outputsTrue() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) - createAndSetViewModel() - wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) + fun activityIn_hasActivityInTrue_outputsTrue() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) + createAndSetViewModel() + wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) - var latest: Boolean? = null - val job = underTest - .home - .isActivityInViewVisible - .onEach { latest = it } - .launchIn(this) + var latest: Boolean? = null + val job = underTest.home.isActivityInViewVisible.onEach { latest = it }.launchIn(this) - val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = false) - wifiRepository.setWifiActivity(activity) - yield() + val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = false) + wifiRepository.setWifiActivity(activity) + yield() - assertThat(latest).isTrue() + assertThat(latest).isTrue() - job.cancel() - } + job.cancel() + } @Test - fun activityIn_hasActivityInFalse_outputsFalse() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) - createAndSetViewModel() - wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) + fun activityIn_hasActivityInFalse_outputsFalse() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) + createAndSetViewModel() + wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) - var latest: Boolean? = null - val job = underTest - .home - .isActivityInViewVisible - .onEach { latest = it } - .launchIn(this) + var latest: Boolean? = null + val job = underTest.home.isActivityInViewVisible.onEach { latest = it }.launchIn(this) - val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = true) - wifiRepository.setWifiActivity(activity) - yield() + val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = true) + wifiRepository.setWifiActivity(activity) + yield() - assertThat(latest).isFalse() + assertThat(latest).isFalse() - job.cancel() - } + job.cancel() + } @Test - fun activityOut_hasActivityOutTrue_outputsTrue() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) - createAndSetViewModel() - wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) + fun activityOut_hasActivityOutTrue_outputsTrue() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) + createAndSetViewModel() + wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) - var latest: Boolean? = null - val job = underTest - .home - .isActivityOutViewVisible - .onEach { latest = it } - .launchIn(this) + var latest: Boolean? = null + val job = underTest.home.isActivityOutViewVisible.onEach { latest = it }.launchIn(this) - val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = true) - wifiRepository.setWifiActivity(activity) - yield() + val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = true) + wifiRepository.setWifiActivity(activity) + yield() - assertThat(latest).isTrue() + assertThat(latest).isTrue() - job.cancel() - } + job.cancel() + } @Test - fun activityOut_hasActivityOutFalse_outputsFalse() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) - createAndSetViewModel() - wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) + fun activityOut_hasActivityOutFalse_outputsFalse() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) + createAndSetViewModel() + wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) - var latest: Boolean? = null - val job = underTest - .home - .isActivityOutViewVisible - .onEach { latest = it } - .launchIn(this) + var latest: Boolean? = null + val job = underTest.home.isActivityOutViewVisible.onEach { latest = it }.launchIn(this) - val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = false) - wifiRepository.setWifiActivity(activity) - yield() + val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = false) + wifiRepository.setWifiActivity(activity) + yield() - assertThat(latest).isFalse() + assertThat(latest).isFalse() - job.cancel() - } + job.cancel() + } @Test - fun activityContainer_hasActivityInTrue_outputsTrue() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) - createAndSetViewModel() - wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) + fun activityContainer_hasActivityInTrue_outputsTrue() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) + createAndSetViewModel() + wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) - var latest: Boolean? = null - val job = underTest - .home - .isActivityContainerVisible - .onEach { latest = it } - .launchIn(this) + var latest: Boolean? = null + val job = + underTest.home.isActivityContainerVisible.onEach { latest = it }.launchIn(this) - val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = false) - wifiRepository.setWifiActivity(activity) - yield() + val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = false) + wifiRepository.setWifiActivity(activity) + yield() - assertThat(latest).isTrue() + assertThat(latest).isTrue() - job.cancel() - } + job.cancel() + } @Test - fun activityContainer_hasActivityOutTrue_outputsTrue() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) - createAndSetViewModel() - wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) + fun activityContainer_hasActivityOutTrue_outputsTrue() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) + createAndSetViewModel() + wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) - var latest: Boolean? = null - val job = underTest - .home - .isActivityContainerVisible - .onEach { latest = it } - .launchIn(this) + var latest: Boolean? = null + val job = + underTest.home.isActivityContainerVisible.onEach { latest = it }.launchIn(this) - val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = true) - wifiRepository.setWifiActivity(activity) - yield() + val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = true) + wifiRepository.setWifiActivity(activity) + yield() - assertThat(latest).isTrue() + assertThat(latest).isTrue() - job.cancel() - } + job.cancel() + } @Test - fun activityContainer_inAndOutTrue_outputsTrue() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) - createAndSetViewModel() - wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) + fun activityContainer_inAndOutTrue_outputsTrue() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) + createAndSetViewModel() + wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) - var latest: Boolean? = null - val job = underTest - .home - .isActivityContainerVisible - .onEach { latest = it } - .launchIn(this) + var latest: Boolean? = null + val job = + underTest.home.isActivityContainerVisible.onEach { latest = it }.launchIn(this) - val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) - wifiRepository.setWifiActivity(activity) - yield() + val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) + wifiRepository.setWifiActivity(activity) + yield() - assertThat(latest).isTrue() + assertThat(latest).isTrue() - job.cancel() - } + job.cancel() + } @Test - fun activityContainer_inAndOutFalse_outputsFalse() = runBlocking(IMMEDIATE) { - whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) - createAndSetViewModel() - wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) + fun activityContainer_inAndOutFalse_outputsFalse() = + runBlocking(IMMEDIATE) { + whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) + createAndSetViewModel() + wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) - var latest: Boolean? = null - val job = underTest - .home - .isActivityContainerVisible - .onEach { latest = it } - .launchIn(this) + var latest: Boolean? = null + val job = + underTest.home.isActivityContainerVisible.onEach { latest = it }.launchIn(this) - val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = false) - wifiRepository.setWifiActivity(activity) - yield() + val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = false) + wifiRepository.setWifiActivity(activity) + yield() - assertThat(latest).isFalse() + assertThat(latest).isFalse() - job.cancel() - } + job.cancel() + } @Test - fun airplaneSpacer_notAirplaneMode_outputsFalse() = runBlocking(IMMEDIATE) { - var latest: Boolean? = null - val job = underTest - .qs - .isAirplaneSpacerVisible - .onEach { latest = it } - .launchIn(this) + fun airplaneSpacer_notAirplaneMode_outputsFalse() = + runBlocking(IMMEDIATE) { + var latest: Boolean? = null + val job = underTest.qs.isAirplaneSpacerVisible.onEach { latest = it }.launchIn(this) - airplaneModeRepository.setIsAirplaneMode(false) - yield() + airplaneModeRepository.setIsAirplaneMode(false) + yield() - assertThat(latest).isFalse() + assertThat(latest).isFalse() - job.cancel() - } + job.cancel() + } @Test - fun airplaneSpacer_airplaneForceHidden_outputsFalse() = runBlocking(IMMEDIATE) { - var latest: Boolean? = null - val job = underTest - .qs - .isAirplaneSpacerVisible - .onEach { latest = it } - .launchIn(this) + fun airplaneSpacer_airplaneForceHidden_outputsFalse() = + runBlocking(IMMEDIATE) { + var latest: Boolean? = null + val job = underTest.qs.isAirplaneSpacerVisible.onEach { latest = it }.launchIn(this) - airplaneModeRepository.setIsAirplaneMode(true) - connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.AIRPLANE)) - yield() + airplaneModeRepository.setIsAirplaneMode(true) + connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.AIRPLANE)) + yield() - assertThat(latest).isFalse() + assertThat(latest).isFalse() - job.cancel() - } + job.cancel() + } @Test - fun airplaneSpacer_airplaneIconVisible_outputsTrue() = runBlocking(IMMEDIATE) { - var latest: Boolean? = null - val job = underTest - .qs - .isAirplaneSpacerVisible - .onEach { latest = it } - .launchIn(this) + fun airplaneSpacer_airplaneIconVisible_outputsTrue() = + runBlocking(IMMEDIATE) { + var latest: Boolean? = null + val job = underTest.qs.isAirplaneSpacerVisible.onEach { latest = it }.launchIn(this) - airplaneModeRepository.setIsAirplaneMode(true) - yield() + airplaneModeRepository.setIsAirplaneMode(true) + yield() - assertThat(latest).isTrue() + assertThat(latest).isTrue() - job.cancel() - } + job.cancel() + } private fun createAndSetViewModel() { // [WifiViewModel] creates its flows as soon as it's instantiated, and some of those flow // creations rely on certain config values that we mock out in individual tests. This method // allows tests to create the view model only after those configs are correctly set up. - underTest = WifiViewModel( - airplaneModeViewModel, - connectivityConstants, - context, - logger, - tableLogBuffer, - interactor, - scope, - statusBarPipelineFlags, - wifiConstants, - ) + underTest = + WifiViewModel( + airplaneModeViewModel, + connectivityConstants, + context, + logger, + tableLogBuffer, + interactor, + scope, + statusBarPipelineFlags, + wifiConstants, + ) } companion object { diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt index fc7436a6b273..586bdc6c8215 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt @@ -27,6 +27,7 @@ import android.view.WindowManager import android.view.accessibility.AccessibilityManager import android.widget.ImageView import android.widget.TextView +import androidx.core.animation.doOnCancel import androidx.test.filters.SmallTest import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.R @@ -361,6 +362,105 @@ class ChipbarCoordinatorTest : SysuiTestCase() { } @Test + fun displayView_loading_animationStarted() { + underTest.displayView( + createChipbarInfo( + Icon.Resource(R.id.check_box, null), + Text.Loaded("text"), + endItem = ChipbarEndItem.Loading, + ) + ) + + assertThat(underTest.loadingDetails!!.animator.isStarted).isTrue() + } + + @Test + fun displayView_notLoading_noAnimation() { + underTest.displayView( + createChipbarInfo( + Icon.Resource(R.id.check_box, null), + Text.Loaded("text"), + endItem = ChipbarEndItem.Error, + ) + ) + + assertThat(underTest.loadingDetails).isNull() + } + + @Test + fun displayView_loadingThenNotLoading_animationStopped() { + underTest.displayView( + createChipbarInfo( + Icon.Resource(R.id.check_box, null), + Text.Loaded("text"), + endItem = ChipbarEndItem.Loading, + ) + ) + + val animator = underTest.loadingDetails!!.animator + var cancelled = false + animator.doOnCancel { cancelled = true } + + underTest.displayView( + createChipbarInfo( + Icon.Resource(R.id.check_box, null), + Text.Loaded("text"), + endItem = ChipbarEndItem.Button(Text.Loaded("button")) {}, + ) + ) + + assertThat(cancelled).isTrue() + assertThat(underTest.loadingDetails).isNull() + } + + @Test + fun displayView_loadingThenHideView_animationStopped() { + underTest.displayView( + createChipbarInfo( + Icon.Resource(R.id.check_box, null), + Text.Loaded("text"), + endItem = ChipbarEndItem.Loading, + ) + ) + + val animator = underTest.loadingDetails!!.animator + var cancelled = false + animator.doOnCancel { cancelled = true } + + underTest.removeView(DEVICE_ID, "TestReason") + + assertThat(cancelled).isTrue() + assertThat(underTest.loadingDetails).isNull() + } + + @Test + fun displayView_loadingThenNewLoading_animationStaysTheSame() { + underTest.displayView( + createChipbarInfo( + Icon.Resource(R.id.check_box, null), + Text.Loaded("text"), + endItem = ChipbarEndItem.Loading, + ) + ) + + val animator = underTest.loadingDetails!!.animator + var cancelled = false + animator.doOnCancel { cancelled = true } + + underTest.displayView( + createChipbarInfo( + Icon.Resource(R.id.check_box, null), + Text.Loaded("new text"), + endItem = ChipbarEndItem.Loading, + ) + ) + + assertThat(underTest.loadingDetails!!.animator).isEqualTo(animator) + assertThat(underTest.loadingDetails!!.animator.isStarted).isTrue() + assertThat(cancelled).isFalse() + } + + @Test fun displayView_vibrationEffect_doubleClickEffect() { underTest.displayView( createChipbarInfo( diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt index abbdab0d41f5..5288608a202d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt @@ -20,17 +20,13 @@ import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import com.android.systemui.SysuiTestCase import com.android.systemui.unfold.UnfoldTransitionProgressProvider -import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener -import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING -import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE +import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING -import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED +import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING +import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE import com.android.systemui.unfold.util.TestFoldStateProvider -import com.android.systemui.util.leak.ReferenceTestUtils.waitForCondition -import com.google.common.truth.Truth.assertThat -import com.google.common.truth.Truth.assertWithMessage import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -45,9 +41,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() { @Before fun setUp() { - progressProvider = PhysicsBasedUnfoldTransitionProgressProvider( - foldStateProvider - ) + progressProvider = PhysicsBasedUnfoldTransitionProgressProvider(foldStateProvider) progressProvider.addCallback(listener) } @@ -79,9 +73,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() { { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }, ) - with(listener.ensureTransitionFinished()) { - assertHasSingleFinishingEvent() - } + with(listener.ensureTransitionFinished()) { assertHasSingleFinishingEvent() } } @Test @@ -150,106 +142,12 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() { { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) }, ) - with(listener.ensureTransitionFinished()) { - assertHasFoldAnimationAtTheEnd() - } - } - - private class TestUnfoldProgressListener : TransitionProgressListener { - - private val recordings: MutableList<UnfoldTransitionRecording> = arrayListOf() - private var currentRecording: UnfoldTransitionRecording? = null - - override fun onTransitionStarted() { - assertWithMessage("Trying to start a transition when it is already in progress") - .that(currentRecording).isNull() - - currentRecording = UnfoldTransitionRecording() - } - - override fun onTransitionProgress(progress: Float) { - assertWithMessage("Received transition progress event when it's not started") - .that(currentRecording).isNotNull() - currentRecording!!.addProgress(progress) - } - - override fun onTransitionFinishing() { - assertWithMessage("Received transition finishing event when it's not started") - .that(currentRecording).isNotNull() - currentRecording!!.onFinishing() - } - - override fun onTransitionFinished() { - assertWithMessage("Received transition finish event when it's not started") - .that(currentRecording).isNotNull() - recordings += currentRecording!! - currentRecording = null - } - - fun ensureTransitionFinished(): UnfoldTransitionRecording { - waitForCondition { recordings.size == 1 } - return recordings.first() - } - - class UnfoldTransitionRecording { - private val progressHistory: MutableList<Float> = arrayListOf() - private var finishingInvocations: Int = 0 - - fun addProgress(progress: Float) { - assertThat(progress).isAtMost(1.0f) - assertThat(progress).isAtLeast(0.0f) - - progressHistory += progress - } - - fun onFinishing() { - finishingInvocations++ - } - - fun assertIncreasingProgress() { - assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) - assertThat(progressHistory).isInOrder() - } - - fun assertDecreasingProgress() { - assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) - assertThat(progressHistory).isInOrder(Comparator.reverseOrder<Float>()) - } - - fun assertFinishedWithUnfold() { - assertThat(progressHistory).isNotEmpty() - assertThat(progressHistory.last()).isEqualTo(1.0f) - } - - fun assertFinishedWithFold() { - assertThat(progressHistory).isNotEmpty() - assertThat(progressHistory.last()).isEqualTo(0.0f) - } - - fun assertHasFoldAnimationAtTheEnd() { - // Check that there are at least a few decreasing events at the end - assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) - assertThat(progressHistory.takeLast(MIN_ANIMATION_EVENTS)) - .isInOrder(Comparator.reverseOrder<Float>()) - assertThat(progressHistory.last()).isEqualTo(0.0f) - } - - fun assertHasSingleFinishingEvent() { - assertWithMessage("onTransitionFinishing callback should be invoked exactly " + - "one time").that(finishingInvocations).isEqualTo(1) - } - } - - private companion object { - private const val MIN_ANIMATION_EVENTS = 5 - } + with(listener.ensureTransitionFinished()) { assertHasFoldAnimationAtTheEnd() } } private fun runOnMainThreadWithInterval(vararg blocks: () -> Unit, intervalMillis: Long = 60) { blocks.forEach { - InstrumentationRegistry.getInstrumentation().runOnMainSync { - it() - } + InstrumentationRegistry.getInstrumentation().runOnMainSync { it() } Thread.sleep(intervalMillis) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiverTest.kt new file mode 100644 index 000000000000..0e7e039e69e2 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiverTest.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.unfold.progress + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class RemoteUnfoldTransitionReceiverTest : SysuiTestCase() { + + private val progressProvider = RemoteUnfoldTransitionReceiver { it.run() } + private val listener = TestUnfoldProgressListener() + + @Before + fun setUp() { + progressProvider.addCallback(listener) + } + + @Test + fun onTransitionStarted_propagated() { + progressProvider.onTransitionStarted() + + listener.assertStarted() + } + + @Test + fun onTransitionProgress_propagated() { + progressProvider.onTransitionStarted() + + progressProvider.onTransitionProgress(0.5f) + + listener.assertLastProgress(0.5f) + } + + @Test + fun onTransitionEnded_propagated() { + progressProvider.onTransitionStarted() + progressProvider.onTransitionProgress(0.5f) + + progressProvider.onTransitionFinished() + + listener.ensureTransitionFinished() + } + + @Test + fun onTransitionStarted_afterCallbackRemoved_notPropagated() { + progressProvider.removeCallback(listener) + + progressProvider.onTransitionStarted() + + listener.assertNotStarted() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/TestUnfoldProgressListener.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/TestUnfoldProgressListener.kt new file mode 100644 index 000000000000..f6532070d720 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/TestUnfoldProgressListener.kt @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.unfold.progress + +import com.android.systemui.unfold.UnfoldTransitionProgressProvider +import com.android.systemui.util.leak.ReferenceTestUtils.waitForCondition +import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage + +/** Listener usable by tests with some handy assertions. */ +class TestUnfoldProgressListener : UnfoldTransitionProgressProvider.TransitionProgressListener { + + private val recordings: MutableList<UnfoldTransitionRecording> = arrayListOf() + private var currentRecording: UnfoldTransitionRecording? = null + + override fun onTransitionStarted() { + assertWithMessage("Trying to start a transition when it is already in progress") + .that(currentRecording) + .isNull() + + currentRecording = UnfoldTransitionRecording() + } + + override fun onTransitionProgress(progress: Float) { + assertWithMessage("Received transition progress event when it's not started") + .that(currentRecording) + .isNotNull() + currentRecording!!.addProgress(progress) + } + + override fun onTransitionFinishing() { + assertWithMessage("Received transition finishing event when it's not started") + .that(currentRecording) + .isNotNull() + currentRecording!!.onFinishing() + } + + override fun onTransitionFinished() { + assertWithMessage("Received transition finish event when it's not started") + .that(currentRecording) + .isNotNull() + recordings += currentRecording!! + currentRecording = null + } + + fun ensureTransitionFinished(): UnfoldTransitionRecording { + waitForCondition { recordings.size == 1 } + return recordings.first() + } + + fun assertStarted() { + assertWithMessage("Transition didn't start").that(currentRecording).isNotNull() + } + + fun assertNotStarted() { + assertWithMessage("Transition started").that(currentRecording).isNull() + } + + fun assertLastProgress(progress: Float) { + currentRecording?.assertLastProgress(progress) ?: error("unfold not in progress.") + } + + class UnfoldTransitionRecording { + private val progressHistory: MutableList<Float> = arrayListOf() + private var finishingInvocations: Int = 0 + + fun addProgress(progress: Float) { + assertThat(progress).isAtMost(1.0f) + assertThat(progress).isAtLeast(0.0f) + + progressHistory += progress + } + + fun onFinishing() { + finishingInvocations++ + } + + fun assertIncreasingProgress() { + assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) + assertThat(progressHistory).isInOrder() + } + + fun assertDecreasingProgress() { + assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) + assertThat(progressHistory).isInOrder(Comparator.reverseOrder<Float>()) + } + + fun assertFinishedWithUnfold() { + assertThat(progressHistory).isNotEmpty() + assertThat(progressHistory.last()).isEqualTo(1.0f) + } + + fun assertFinishedWithFold() { + assertThat(progressHistory).isNotEmpty() + assertThat(progressHistory.last()).isEqualTo(0.0f) + } + + fun assertHasFoldAnimationAtTheEnd() { + // Check that there are at least a few decreasing events at the end + assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) + assertThat(progressHistory.takeLast(MIN_ANIMATION_EVENTS)) + .isInOrder(Comparator.reverseOrder<Float>()) + assertThat(progressHistory.last()).isEqualTo(0.0f) + } + + fun assertHasSingleFinishingEvent() { + assertWithMessage( + "onTransitionFinishing callback should be invoked exactly " + "one time" + ) + .that(finishingInvocations) + .isEqualTo(1) + } + + fun assertLastProgress(progress: Float) { + assertThat(progressHistory.last()).isEqualTo(progress) + } + } + + private companion object { + private const val MIN_ANIMATION_EVENTS = 5 + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt index 8660d097c0df..0257ebd5c6d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt @@ -28,7 +28,6 @@ import android.os.UserHandle import android.os.UserManager import android.provider.Settings import androidx.test.filters.SmallTest -import com.android.internal.R.drawable.ic_account_circle import com.android.internal.logging.UiEventLogger import com.android.systemui.GuestResetOrExitSessionReceiver import com.android.systemui.GuestResumeSessionReceiver @@ -87,6 +86,7 @@ class UserInteractorTest : SysuiTestCase() { @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var manager: UserManager + @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode @Mock private lateinit var activityManager: ActivityManager @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock private lateinit var devicePolicyManager: DevicePolicyManager @@ -145,6 +145,7 @@ class UserInteractorTest : SysuiTestCase() { featureFlags = featureFlags, ), manager = manager, + headlessSystemUserMode = headlessSystemUserMode, applicationScope = testScope.backgroundScope, telephonyInteractor = TelephonyInteractor( @@ -848,6 +849,50 @@ class UserInteractorTest : SysuiTestCase() { assertThat(selectedUser()).isNotNull() } + @Test + fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled() = + testScope.runTest { + keyguardRepository.setKeyguardShowing(true) + whenever(manager.getUserSwitchability(any())) + .thenReturn(UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED) + val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList() + userRepository.setUserInfos(userInfos) + userRepository.setSelectedUserInfo(userInfos[1]) + userRepository.setSettings( + UserSwitcherSettingsModel( + isUserSwitcherEnabled = true, + isAddUsersFromLockscreen = true + ) + ) + + runCurrent() + underTest.userRecords.value + .filter { it.info == null } + .forEach { action -> assertThat(action.isSwitchToEnabled).isFalse() } + } + + @Test + fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled_HeadlessMode() = + testScope.runTest { + keyguardRepository.setKeyguardShowing(true) + whenever(headlessSystemUserMode.isHeadlessSystemUserMode()).thenReturn(true) + whenever(manager.isUserUnlocked(anyInt())).thenReturn(false) + val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList() + userRepository.setUserInfos(userInfos) + userRepository.setSelectedUserInfo(userInfos[1]) + userRepository.setSettings( + UserSwitcherSettingsModel( + isUserSwitcherEnabled = true, + isAddUsersFromLockscreen = true + ) + ) + + runCurrent() + underTest.userRecords.value + .filter { it.info == null } + .forEach { action -> assertThat(action.isSwitchToEnabled).isFalse() } + } + private fun assertUsers( models: List<UserModel>?, count: Int, diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt index 8a35cb05038a..2fedb875b3e3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt @@ -41,6 +41,7 @@ import com.android.systemui.telephony.domain.interactor.TelephonyInteractor import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.domain.interactor.GuestUserInteractor +import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode import com.android.systemui.user.domain.interactor.RefreshUsersScheduler import com.android.systemui.user.domain.interactor.UserInteractor import com.android.systemui.util.mockito.mock @@ -71,6 +72,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() { @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var activityManager: ActivityManager @Mock private lateinit var manager: UserManager + @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var uiEventLogger: UiEventLogger @@ -252,6 +254,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() { ), featureFlags = featureFlags, manager = manager, + headlessSystemUserMode = headlessSystemUserMode, applicationScope = testScope.backgroundScope, telephonyInteractor = TelephonyInteractor( diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt index 1337d1bdb7ca..166b90943847 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt @@ -41,6 +41,7 @@ import com.android.systemui.telephony.domain.interactor.TelephonyInteractor import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.domain.interactor.GuestUserInteractor +import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode import com.android.systemui.user.domain.interactor.RefreshUsersScheduler import com.android.systemui.user.domain.interactor.UserInteractor import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper @@ -72,6 +73,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() { @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var activityManager: ActivityManager @Mock private lateinit var manager: UserManager + @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var uiEventLogger: UiEventLogger @@ -154,6 +156,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() { ), featureFlags = featureFlags, manager = manager, + headlessSystemUserMode = headlessSystemUserMode, applicationScope = testScope.backgroundScope, telephonyInteractor = TelephonyInteractor( diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java index 5ef62c1e7e8d..b367a603ec67 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java @@ -60,6 +60,11 @@ public class ConditionalCoreStartableTest extends SysuiTestCase { mCallback = callback; } + public FakeConditionalCoreStartable(Monitor monitor, Callback callback) { + super(monitor); + mCallback = callback; + } + @Override protected void onStart() { mCallback.onStart(); @@ -122,6 +127,31 @@ public class ConditionalCoreStartableTest extends SysuiTestCase { verify(mMonitor).removeSubscription(mSubscriptionToken); } + @Test + public void testOnStartCallbackWithNoConditions() { + final CoreStartable coreStartable = + new FakeConditionalCoreStartable(mMonitor, + mCallback); + + when(mMonitor.addSubscription(any())).thenReturn(mSubscriptionToken); + coreStartable.start(); + + final ArgumentCaptor<Monitor.Subscription> subscriptionCaptor = ArgumentCaptor.forClass( + Monitor.Subscription.class); + verify(mMonitor).addSubscription(subscriptionCaptor.capture()); + + final Monitor.Subscription subscription = subscriptionCaptor.getValue(); + + assertThat(subscription.getConditions()).isEmpty(); + + verify(mCallback, never()).onStart(); + + subscription.getCallback().onConditionsChanged(true); + + verify(mCallback).onStart(); + verify(mMonitor).removeSubscription(mSubscriptionToken); + } + /** * Verifies that {@link ConditionalCoreStartable#bootCompleted()} ()} is predicated on diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java b/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java new file mode 100644 index 000000000000..7ee05d02b3cb --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.condition; + +import androidx.annotation.NonNull; + +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; + +/** + * {@link SelfExecutingMonitor} creates a monitor that independently executes its logic through + * a {@link FakeExecutor}, which is ran at when a subscription is added and removed. + */ +public class SelfExecutingMonitor extends Monitor { + private final FakeExecutor mExecutor; + + /** + * Default constructor that allows specifying the FakeExecutor to use. + */ + public SelfExecutingMonitor(FakeExecutor executor) { + super(executor); + mExecutor = executor; + } + + @Override + public Subscription.Token addSubscription(@NonNull Subscription subscription) { + final Subscription.Token result = super.addSubscription(subscription); + mExecutor.runAllReady(); + return result; + } + + @Override + public void removeSubscription(@NonNull Subscription.Token token) { + super.removeSubscription(token); + mExecutor.runNextReady(); + } + + /** + * Creates a {@link SelfExecutingMonitor} with a self-managed {@link FakeExecutor}. Use only + * for cases where condition state only will be set at when a subscription is added. + */ + public static SelfExecutingMonitor createInstance() { + final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); + final FakeExecutor mExecutor = new FakeExecutor(mFakeSystemClock); + return new SelfExecutingMonitor(mExecutor); + } +} diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldRemoteModule.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldRemoteModule.kt new file mode 100644 index 000000000000..b395d9c07662 --- /dev/null +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldRemoteModule.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.unfold + +import com.android.systemui.unfold.config.UnfoldTransitionConfig +import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver +import com.android.systemui.unfold.util.ATraceLoggerTransitionProgressListener +import dagger.Module +import dagger.Provides +import java.util.Optional +import javax.inject.Provider +import javax.inject.Singleton + +/** Binds classes needed to provide unfold transition progresses to another process. */ +@Module +class UnfoldRemoteModule { + @Provides + @Singleton + fun provideTransitionProvider( + config: UnfoldTransitionConfig, + traceListener: ATraceLoggerTransitionProgressListener, + remoteReceiverProvider: Provider<RemoteUnfoldTransitionReceiver>, + ): Optional<RemoteUnfoldTransitionReceiver> { + if (!config.isEnabled) { + return Optional.empty() + } + val remoteReceiver = remoteReceiverProvider.get() + remoteReceiver.addCallback(traceListener) + return Optional.of(remoteReceiver) + } +} diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt index cfb959e51d4e..068347cfe9d8 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt @@ -24,6 +24,7 @@ import android.view.IWindowManager import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.dagger.UnfoldMain import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg +import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver import com.android.systemui.unfold.updates.FoldProvider import com.android.systemui.unfold.updates.RotationChangeProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider @@ -68,3 +69,38 @@ interface UnfoldSharedComponent { val unfoldTransitionProvider: Optional<UnfoldTransitionProgressProvider> val rotationChangeProvider: RotationChangeProvider } + +/** + * Generates a [RemoteTransitionProgress] usable to receive unfold transition progress from another + * process. + */ +@Singleton +@Component(modules = [UnfoldRemoteModule::class]) +interface RemoteUnfoldSharedComponent { + + @Component.Factory + interface Factory { + fun create( + @BindsInstance context: Context, + @BindsInstance config: UnfoldTransitionConfig, + @BindsInstance @UnfoldMain executor: Executor, + @BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor, + @BindsInstance windowManager: IWindowManager, + @BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String, + ): RemoteUnfoldSharedComponent + } + + val remoteTransitionProgress: Optional<RemoteUnfoldTransitionReceiver> + val rotationChangeProvider: RotationChangeProvider +} + +/** + * Usable to receive and propagate unfold transition progresses + * + * All unfold events received by [remoteReceiver] will be propagated to [localProvider]. + * [remoteReceiver] is meant to receive events from a remote process (E.g. from a binder service). + */ +data class RemoteTransitionProgress( + val localProvider: UnfoldTransitionProgressProvider, + val remoteReceiver: UnfoldTransitionProgressProvider.TransitionProgressListener +) diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt index 31616fa54bf4..5ffc094b88b3 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt @@ -19,6 +19,7 @@ package com.android.systemui.unfold import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider +import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder import com.android.systemui.unfold.updates.DeviceFoldStateProvider import com.android.systemui.unfold.updates.FoldStateProvider import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider @@ -102,4 +103,16 @@ internal class UnfoldSharedInternalModule { EmptyHingeAngleProvider } } + + @Provides + @Singleton + fun provideProgressForwarder( + config: UnfoldTransitionConfig, + progressForwarder: Provider<UnfoldTransitionProgressForwarder> + ): Optional<UnfoldTransitionProgressForwarder> { + if (!config.isEnabled) { + return Optional.empty() + } + return Optional.of(progressForwarder.get()) + } } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt index aa93c6290145..8eb79df55496 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt @@ -63,3 +63,26 @@ fun createUnfoldSharedComponent( tracingTagPrefix, windowManager, ) + +/** + * Factory for [RemoteUnfoldSharedComponent]. + * + * Wraps [DaggerRemoteUnfoldSharedComponent] (that is autogenerated), for better discoverability. + */ +fun createRemoteUnfoldSharedComponent( + context: Context, + config: UnfoldTransitionConfig, + mainExecutor: Executor, + singleThreadBgExecutor: Executor, + tracingTagPrefix: String, + windowManager: IWindowManager, + ): RemoteUnfoldSharedComponent = + DaggerRemoteUnfoldSharedComponent.factory() + .create( + context, + config, + mainExecutor, + singleThreadBgExecutor, + windowManager, + tracingTagPrefix, + ) diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/IUnfoldAnimation.aidl b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/IUnfoldAnimation.aidl new file mode 100644 index 000000000000..07a1db4183ae --- /dev/null +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/IUnfoldAnimation.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.unfold.progress; + + +import com.android.systemui.unfold.progress.IUnfoldTransitionListener; + + +/** + * Interface exposed by System UI to allow remote process to register for unfold animation events. + */ +oneway interface IUnfoldAnimation { + + /** + * Sets a listener for the animation. + * + * Only one listener is supported. If there are multiple, the earlier one will be overridden. + */ + void setListener(in IUnfoldTransitionListener listener); +} diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/IUnfoldTransitionListener.aidl b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/IUnfoldTransitionListener.aidl new file mode 100644 index 000000000000..8f46b1b4a4be --- /dev/null +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/IUnfoldTransitionListener.aidl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.unfold.progress; + + +/** + * Implemented by remote processes to receive unfold animation events from System UI. + */ +oneway interface IUnfoldTransitionListener { + /** + * Sent when unfold animation started. + */ + void onTransitionStarted() = 1; + + /** + * Sent when unfold animation progress changes. + */ + void onTransitionProgress(float progress) = 2; + + /** + * Sent when unfold animation finished. + */ + void onTransitionFinished() = 3; +} diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiver.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiver.kt new file mode 100644 index 000000000000..5e4bcc97520e --- /dev/null +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiver.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.unfold.progress + +import com.android.systemui.unfold.UnfoldTransitionProgressProvider +import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener +import com.android.systemui.unfold.dagger.UnfoldMain +import java.util.concurrent.Executor +import javax.inject.Inject + +/** + * Receives unfold events from remote senders (System UI). + * + * A binder to an instance to this class (created with [RemoteUnfoldTransitionReceiver.asBinder]) + * should be sent to the remote process providing events. + */ +class RemoteUnfoldTransitionReceiver +@Inject +constructor(@UnfoldMain private val executor: Executor) : + UnfoldTransitionProgressProvider, IUnfoldTransitionListener.Stub() { + + private val listeners: MutableSet<TransitionProgressListener> = mutableSetOf() + + override fun onTransitionStarted() { + executor.execute { listeners.forEach { it.onTransitionStarted() } } + } + + override fun onTransitionProgress(progress: Float) { + executor.execute { listeners.forEach { it.onTransitionProgress(progress) } } + } + + override fun onTransitionFinished() { + executor.execute { listeners.forEach { it.onTransitionFinished() } } + } + + override fun addCallback(listener: TransitionProgressListener) { + listeners += listener + } + + override fun removeCallback(listener: TransitionProgressListener) { + listeners -= listener + } + + override fun destroy() { + listeners.clear() + } +} diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldTransitionProgressForwarder.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldTransitionProgressForwarder.kt new file mode 100644 index 000000000000..b6545215690d --- /dev/null +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/UnfoldTransitionProgressForwarder.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.android.systemui.unfold.progress + +import android.os.RemoteException +import android.util.Log +import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener +import javax.inject.Inject + +/** Forwards received unfold events to [remoteListener], when present. */ +class UnfoldTransitionProgressForwarder @Inject constructor() : + TransitionProgressListener, IUnfoldAnimation.Stub() { + + private var remoteListener: IUnfoldTransitionListener? = null + + override fun onTransitionStarted() { + try { + Log.d(TAG, "onTransitionStarted") + remoteListener?.onTransitionStarted() + } catch (e: RemoteException) { + Log.e(TAG, "Failed call onTransitionStarted", e) + } + } + + override fun onTransitionFinished() { + try { + Log.d(TAG, "onTransitionFinished") + remoteListener?.onTransitionFinished() + } catch (e: RemoteException) { + Log.e(TAG, "Failed call onTransitionFinished", e) + } + } + + override fun onTransitionProgress(progress: Float) { + try { + remoteListener?.onTransitionProgress(progress) + } catch (e: RemoteException) { + Log.e(TAG, "Failed call onTransitionProgress", e) + } + } + + override fun setListener(listener: IUnfoldTransitionListener?) { + remoteListener = listener + } + + companion object { + private val TAG = UnfoldTransitionProgressForwarder::class.java.simpleName + } +} diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 0589cfc0967b..cf880eba20f7 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -1512,6 +1512,7 @@ import java.util.concurrent.atomic.AtomicBoolean; case MSG_I_BT_SERVICE_DISCONNECTED_PROFILE: if (msg.arg1 != BluetoothProfile.HEADSET) { synchronized (mDeviceStateLock) { + mBtHelper.onBtProfileDisconnected(msg.arg1); mDeviceInventory.onBtProfileDisconnected(msg.arg1); } } else { diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 6cd42f87aede..f95982138564 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -279,7 +279,11 @@ public class BtHelper { } AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent( AudioServiceEvents.VolumeEvent.VOL_SET_AVRCP_VOL, index)); - mA2dp.setAvrcpAbsoluteVolume(index); + try { + mA2dp.setAvrcpAbsoluteVolume(index); + } catch (Exception e) { + Log.e(TAG, "Exception while changing abs volume", e); + } } /*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec int getA2dpCodec( @@ -287,7 +291,12 @@ public class BtHelper { if (mA2dp == null) { return AudioSystem.AUDIO_FORMAT_DEFAULT; } - final BluetoothCodecStatus btCodecStatus = mA2dp.getCodecStatus(device); + final BluetoothCodecStatus btCodecStatus = null; + try { + mA2dp.getCodecStatus(device); + } catch (Exception e) { + Log.e(TAG, "Exception while getting status of " + device, e); + } if (btCodecStatus == null) { return AudioSystem.AUDIO_FORMAT_DEFAULT; } @@ -421,7 +430,11 @@ public class BtHelper { } AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent( AudioServiceEvents.VolumeEvent.VOL_SET_LE_AUDIO_VOL, index, maxIndex)); - mLeAudio.setVolume(volume); + try { + mLeAudio.setVolume(volume); + } catch (Exception e) { + Log.e(TAG, "Exception while setting LE volume", e); + } } /*package*/ synchronized void setHearingAidVolume(int index, int streamType, @@ -447,7 +460,11 @@ public class BtHelper { AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent( AudioServiceEvents.VolumeEvent.VOL_SET_HEARING_AID_VOL, index, gainDB)); } - mHearingAid.setVolume(gainDB); + try { + mHearingAid.setVolume(gainDB); + } catch (Exception e) { + Log.i(TAG, "Exception while setting hearing aid volume", e); + } } /*package*/ synchronized void onBroadcastScoConnectionState(int state) { @@ -487,6 +504,35 @@ public class BtHelper { mBluetoothHeadset = null; } + //@GuardedBy("AudioDeviceBroker.mDeviceStateLock") + /*package*/ synchronized void onBtProfileDisconnected(int profile) { + switch (profile) { + case BluetoothProfile.A2DP: + mA2dp = null; + break; + case BluetoothProfile.HEARING_AID: + mHearingAid = null; + break; + case BluetoothProfile.LE_AUDIO: + mLeAudio = null; + break; + + case BluetoothProfile.A2DP_SINK: + case BluetoothProfile.LE_AUDIO_BROADCAST: + // shouldn't be received here as profile doesn't involve BtHelper + Log.e(TAG, "onBtProfileDisconnected: Not a profile handled by BtHelper " + + BluetoothProfile.getProfileName(profile)); + break; + + default: + // Not a valid profile to disconnect + Log.e(TAG, "onBtProfileDisconnected: Not a valid profile to disconnect " + + BluetoothProfile.getProfileName(profile)); + break; + } + } + + //@GuardedBy("AudioDeviceBroker.mDeviceStateLock") /*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) { if (profile == BluetoothProfile.HEADSET) { onHeadsetProfileConnected((BluetoothHeadset) proxy); @@ -672,7 +718,6 @@ public class BtHelper { public void onServiceConnected(int profile, BluetoothProfile proxy) { switch(profile) { case BluetoothProfile.A2DP: - case BluetoothProfile.A2DP_SINK: case BluetoothProfile.HEADSET: case BluetoothProfile.HEARING_AID: case BluetoothProfile.LE_AUDIO: @@ -682,6 +727,10 @@ public class BtHelper { mDeviceBroker.postBtProfileConnected(profile, proxy); break; + case BluetoothProfile.A2DP_SINK: + // no A2DP sink functionality handled by BtHelper + case BluetoothProfile.LE_AUDIO_BROADCAST: + // no broadcast functionality handled by BtHelper default: break; } @@ -690,14 +739,19 @@ public class BtHelper { switch (profile) { case BluetoothProfile.A2DP: - case BluetoothProfile.A2DP_SINK: case BluetoothProfile.HEADSET: case BluetoothProfile.HEARING_AID: case BluetoothProfile.LE_AUDIO: - case BluetoothProfile.LE_AUDIO_BROADCAST: + AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( + "BT profile service: disconnecting " + + BluetoothProfile.getProfileName(profile) + " profile")); mDeviceBroker.postBtProfileDisconnected(profile); break; + case BluetoothProfile.A2DP_SINK: + // no A2DP sink functionality handled by BtHelper + case BluetoothProfile.LE_AUDIO_BROADCAST: + // no broadcast functionality handled by BtHelper default: break; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index 787bfb00a554..7d390415952e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -228,7 +228,16 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession> @Override public void onError(int errorCode, int vendorCode) { - super.onError(errorCode, vendorCode); + if (getContext().getResources().getBoolean(R.bool.config_powerPressMapping) + && errorCode == BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR + && vendorCode == getContext().getResources() + .getInteger(R.integer.config_powerPressCode)) { + // Translating vendor code to internal code + super.onError(BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED, + 0 /* vendorCode */); + } else { + super.onError(errorCode, vendorCode); + } if (errorCode == BiometricFingerprintConstants.FINGERPRINT_ERROR_BAD_CALIBRATION) { BiometricNotificationUtils.showBadCalibrationNotification(getContext()); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java index 612d90670888..14b19fb9461a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java @@ -37,6 +37,7 @@ import android.os.RemoteException; import android.util.Slog; import android.view.accessibility.AccessibilityManager; +import com.android.internal.R; import com.android.server.biometrics.HardwareAuthTokenUtils; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; @@ -143,7 +144,17 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps } }); mCallback.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH); - super.onAcquired(acquiredInfo, vendorCode); + + if (getContext().getResources().getBoolean(R.bool.config_powerPressMapping) + && acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR + && vendorCode == getContext().getResources() + .getInteger(R.integer.config_powerPressCode)) { + // Translating vendor code to internal code + super.onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED, + 0 /* vendorCode */); + } else { + super.onAcquired(acquiredInfo, vendorCode); + } } @Override @@ -270,8 +281,5 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps } @Override - public void onPowerPressed() { - onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED, - 0 /* vendorCode */); - } + public void onPowerPressed() {} } diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 0ee25e2e03e7..bb44ddf98394 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -137,6 +137,8 @@ import javax.xml.datatype.DatatypeConfigurationException; * <refreshRate> * <lowerBlockingZoneConfigs> * <defaultRefreshRate>75</defaultRefreshRate> + * <defaultRefreshRateInHbmHdr>75</defaultRefreshRateInHbmHdr> + * <defaultRefreshRateInHbmSunlight>75</defaultRefreshRateInHbmSunlight> * <blockingZoneThreshold> * <displayBrightnessPoint> * <lux>50</lux> @@ -404,6 +406,7 @@ public class DisplayDeviceConfig { private static final long STABLE_FLAG = 1L << 62; private static final int DEFAULT_PEAK_REFRESH_RATE = 0; private static final int DEFAULT_REFRESH_RATE = 60; + private static final int DEFAULT_REFRESH_RATE_IN_HBM = 0; private static final int DEFAULT_LOW_REFRESH_RATE = 60; private static final int DEFAULT_HIGH_REFRESH_RATE = 0; private static final int[] DEFAULT_BRIGHTNESS_THRESHOLDS = new int[]{}; @@ -585,6 +588,15 @@ public class DisplayDeviceConfig { private int mDefaultRefreshRate = DEFAULT_REFRESH_RATE; /** + * Default refresh rate while the device has high brightness mode enabled for HDR. + */ + private int mDefaultRefreshRateInHbmHdr = DEFAULT_REFRESH_RATE_IN_HBM; + + /** + * Default refresh rate while the device has high brightness mode enabled for Sunlight. + */ + private int mDefaultRefreshRateInHbmSunlight = DEFAULT_REFRESH_RATE_IN_HBM; + /** * Default refresh rate in the high zone defined by brightness and ambient thresholds. * If non-positive, then the refresh rate is unchanged even if thresholds are configured. */ @@ -1325,8 +1337,7 @@ public class DisplayDeviceConfig { * @return Default refresh rate while the device has high brightness mode enabled for HDR. */ public int getDefaultRefreshRateInHbmHdr() { - return mContext.getResources().getInteger( - R.integer.config_defaultRefreshRateInHbmHdr); + return mDefaultRefreshRateInHbmHdr; } /** @@ -1334,8 +1345,7 @@ public class DisplayDeviceConfig { * high lux. */ public int getDefaultRefreshRateInHbmSunlight() { - return mContext.getResources().getInteger( - R.integer.config_defaultRefreshRateInHbmSunlight); + return mDefaultRefreshRateInHbmSunlight; } /** @@ -1491,6 +1501,8 @@ public class DisplayDeviceConfig { + ", mDefaultHighBlockingZoneRefreshRate= " + mDefaultHighBlockingZoneRefreshRate + ", mDefaultPeakRefreshRate= " + mDefaultPeakRefreshRate + ", mDefaultRefreshRate= " + mDefaultRefreshRate + + ", mDefaultRefreshRateInHbmHdr= " + mDefaultRefreshRateInHbmHdr + + ", mDefaultRefreshRateInHbmSunlight= " + mDefaultRefreshRateInHbmSunlight + ", mLowDisplayBrightnessThresholds= " + Arrays.toString(mLowDisplayBrightnessThresholds) + ", mLowAmbientBrightnessThresholds= " @@ -1806,6 +1818,7 @@ public class DisplayDeviceConfig { : refreshRateConfigs.getHigherBlockingZoneConfigs(); loadPeakDefaultRefreshRate(refreshRateConfigs); loadDefaultRefreshRate(refreshRateConfigs); + loadDefaultRefreshRateInHbm(refreshRateConfigs); loadLowerRefreshRateBlockingZones(lowerBlockingZoneConfig); loadHigherRefreshRateBlockingZones(higherBlockingZoneConfig); } @@ -1830,6 +1843,26 @@ public class DisplayDeviceConfig { } } + private void loadDefaultRefreshRateInHbm(RefreshRateConfigs refreshRateConfigs) { + if (refreshRateConfigs != null + && refreshRateConfigs.getDefaultRefreshRateInHbmHdr() != null) { + mDefaultRefreshRateInHbmHdr = refreshRateConfigs.getDefaultRefreshRateInHbmHdr() + .intValue(); + } else { + mDefaultRefreshRateInHbmHdr = mContext.getResources().getInteger( + R.integer.config_defaultRefreshRateInHbmHdr); + } + + if (refreshRateConfigs != null + && refreshRateConfigs.getDefaultRefreshRateInHbmSunlight() != null) { + mDefaultRefreshRateInHbmSunlight = + refreshRateConfigs.getDefaultRefreshRateInHbmSunlight().intValue(); + } else { + mDefaultRefreshRateInHbmSunlight = mContext.getResources().getInteger( + R.integer.config_defaultRefreshRateInHbmSunlight); + } + } + /** * Loads the refresh rate configurations pertaining to the upper blocking zones. */ diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java index 61f792809525..f74356debd0f 100644 --- a/services/core/java/com/android/server/dreams/DreamController.java +++ b/services/core/java/com/android/server/dreams/DreamController.java @@ -270,7 +270,7 @@ final class DreamController { try { service.asBinder().linkToDeath(mCurrentDream, 0); service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze, - mCurrentDream.mDreamingStartedCallback); + mCurrentDream.mIsPreviewMode, mCurrentDream.mDreamingStartedCallback); } catch (RemoteException ex) { Slog.e(TAG, "The dream service died unexpectedly.", ex); stopDream(true /*immediate*/, "attach failed"); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index faa219e89aa9..cbbee5dc5755 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -4831,6 +4831,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid() + " token: " + token); return; + } else { + // Called with current IME's token. + if (mMethodMap.get(id) != null + && mSettings.getEnabledInputMethodListWithFilterLocked( + (info) -> info.getId().equals(id)).isEmpty()) { + throw new IllegalStateException("Requested IME is not enabled: " + id); + } } final long ident = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java index dc5299077cc9..1fb00eff86d7 100644 --- a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java +++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java @@ -16,6 +16,8 @@ package com.android.server.location.injector; +import static com.android.server.location.LocationManagerService.TAG; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -23,6 +25,7 @@ import android.content.IntentFilter; import android.os.SystemClock; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; +import android.util.Log; import com.android.server.FgThread; @@ -67,8 +70,12 @@ public class SystemEmergencyHelper extends EmergencyHelper { } synchronized (SystemEmergencyHelper.this) { - mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber( - intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER)); + try { + mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber( + intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER)); + } catch (IllegalStateException e) { + Log.w(TAG, "Failed to call TelephonyManager.isEmergencyNumber().", e); + } } } }, new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL)); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 651bb930c49b..5d1a5810a01e 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -3262,8 +3262,7 @@ public final class PowerManagerService extends SystemService } final PowerGroup powerGroup = mPowerGroups.get(groupId); wakefulness = powerGroup.getWakefulnessLocked(); - if ((wakefulness == WAKEFULNESS_DREAMING || wakefulness == WAKEFULNESS_DOZING) && - powerGroup.isSandmanSummonedLocked() && powerGroup.isReadyLocked()) { + if (powerGroup.isSandmanSummonedLocked() && powerGroup.isReadyLocked()) { startDreaming = canDreamLocked(powerGroup) || canDozeLocked(powerGroup); powerGroup.setSandmanSummonedLocked(/* isSandmanSummoned= */ false); } else { diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index cf7d5d9548fd..8e9a21490645 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -2200,7 +2200,7 @@ public class DisplayPolicy { * Called when an app has started replacing its main window. */ void addRelaunchingApp(ActivityRecord app) { - if (mSystemBarColorApps.contains(app)) { + if (mSystemBarColorApps.contains(app) && !app.hasStartingWindow()) { mRelaunchingSystemBarColorApps.add(app); } } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 00e318816a74..db8079a9cd2f 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -45,6 +45,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.TransitionFlags; import static android.view.WindowManager.TransitionType; import static android.view.WindowManager.transitTypeToString; +import static android.window.TaskFragmentAnimationParams.DEFAULT_ANIMATION_BACKGROUND_COLOR; import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS; import static android.window.TransitionInfo.FLAG_FILLS_TASK; import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; @@ -1736,7 +1737,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { ? activityRecord.getOrganizedTaskFragment() : taskFragment.getOrganizedTaskFragment(); if (organizedTf != null && organizedTf.getAnimationParams() - .getAnimationBackgroundColor() != 0) { + .getAnimationBackgroundColor() != DEFAULT_ANIMATION_BACKGROUND_COLOR) { // This window is embedded and has an animation background color set on the // TaskFragment. Pass this color with this window, so the handler can use it as // the animation background color if needed, @@ -1748,10 +1749,11 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { final Task parentTask = activityRecord != null ? activityRecord.getTask() : taskFragment.getTask(); - backgroundColor = ColorUtils.setAlphaComponent( - parentTask.getTaskDescription().getBackgroundColor(), 255); + backgroundColor = parentTask.getTaskDescription().getBackgroundColor(); } - change.setBackgroundColor(backgroundColor); + // Set to opaque for animation background to prevent it from exposing the blank + // background or content below. + change.setBackgroundColor(ColorUtils.setAlphaComponent(backgroundColor, 255)); } change.setRotation(info.mRotation, endRotation); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 9a20354bcf81..ce032442e4af 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -33,6 +33,7 @@ import static android.os.UserHandle.USER_NULL; import static android.view.SurfaceControl.Transaction; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; import static android.view.WindowManager.TRANSIT_CHANGE; +import static android.window.TaskFragmentAnimationParams.DEFAULT_ANIMATION_BACKGROUND_COLOR; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; @@ -3168,7 +3169,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< ? activityRecord.getOrganizedTaskFragment() : taskFragment.getOrganizedTaskFragment(); if (organizedTf != null && organizedTf.getAnimationParams() - .getAnimationBackgroundColor() != 0) { + .getAnimationBackgroundColor() != DEFAULT_ANIMATION_BACKGROUND_COLOR) { // This window is embedded and has an animation background color set on the // TaskFragment. Pass this color with this window, so the handler can use it // as the animation background color if needed, @@ -3181,11 +3182,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< final Task parentTask = activityRecord != null ? activityRecord.getTask() : taskFragment.getTask(); - backgroundColorForTransition = ColorUtils.setAlphaComponent( - parentTask.getTaskDescription().getBackgroundColor(), 255); + backgroundColorForTransition = parentTask.getTaskDescription() + .getBackgroundColor(); } } - animationRunnerBuilder.setTaskBackgroundColor(backgroundColorForTransition); + // Set to opaque for animation background to prevent it from exposing the blank + // background or content below. + animationRunnerBuilder.setTaskBackgroundColor(ColorUtils.setAlphaComponent( + backgroundColorForTransition, 255)); } animationRunnerBuilder.build() diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 03b3ef0b4ee5..52f2b6351265 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -6029,7 +6029,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP Slog.i(TAG, "finishDrawing of orientation change: " + this + " " + duration + "ms"); mOrientationChangeRedrawRequestTime = 0; } else if (mActivityRecord != null && mActivityRecord.mRelaunchStartTime != 0 - && mActivityRecord.findMainWindow() == this) { + && mActivityRecord.findMainWindow(false /* includeStartingApp */) == this) { final long duration = SystemClock.elapsedRealtime() - mActivityRecord.mRelaunchStartTime; Slog.i(TAG, "finishDrawing of relaunch: " + this + " " + duration + "ms"); diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index abe48f894e59..91a11380c81c 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -472,6 +472,14 @@ minOccurs="0" maxOccurs="1"> <xs:annotation name="final"/> </xs:element> + <xs:element name="defaultRefreshRateInHbmHdr" type="xs:nonNegativeInteger" + minOccurs="0" maxOccurs="1"> + <xs:annotation name="final"/> + </xs:element> + <xs:element name="defaultRefreshRateInHbmSunlight" type="xs:nonNegativeInteger" + minOccurs="0" maxOccurs="1"> + <xs:annotation name="final"/> + </xs:element> <xs:element name="lowerBlockingZoneConfigs" type="blockingZoneConfig" minOccurs="0" maxOccurs="1"> <xs:annotation name="final"/> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index 2c97af55f092..1110d86e1fc1 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -188,10 +188,14 @@ package com.android.server.display.config { ctor public RefreshRateConfigs(); method public final java.math.BigInteger getDefaultPeakRefreshRate(); method public final java.math.BigInteger getDefaultRefreshRate(); + method public final java.math.BigInteger getDefaultRefreshRateInHbmHdr(); + method public final java.math.BigInteger getDefaultRefreshRateInHbmSunlight(); method public final com.android.server.display.config.BlockingZoneConfig getHigherBlockingZoneConfigs(); method public final com.android.server.display.config.BlockingZoneConfig getLowerBlockingZoneConfigs(); method public final void setDefaultPeakRefreshRate(java.math.BigInteger); method public final void setDefaultRefreshRate(java.math.BigInteger); + method public final void setDefaultRefreshRateInHbmHdr(java.math.BigInteger); + method public final void setDefaultRefreshRateInHbmSunlight(java.math.BigInteger); method public final void setHigherBlockingZoneConfigs(com.android.server.display.config.BlockingZoneConfig); method public final void setLowerBlockingZoneConfigs(com.android.server.display.config.BlockingZoneConfig); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java index 3c735e335e75..4915c642abd9 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java @@ -16,6 +16,8 @@ package com.android.server.biometrics.sensors.fingerprint.aidl; +import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -35,6 +37,7 @@ import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.content.ComponentName; +import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.common.ICancellationSignal; import android.hardware.biometrics.common.OperationContext; @@ -54,6 +57,7 @@ import android.testing.TestableContext; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.internal.R; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; import com.android.server.biometrics.log.CallbackWithProbe; @@ -335,6 +339,21 @@ public class FingerprintAuthenticationClientTest { showHideOverlay(c -> c.onLockoutPermanent()); } + @Test + public void testPowerPressForwardsErrorMessage() throws RemoteException { + final FingerprintAuthenticationClient client = createClient(); + final int testVendorPowerPressCode = 1; + when(mContext.getOrCreateTestableResources().getResources() + .getBoolean(R.bool.config_powerPressMapping)).thenReturn(true); + when(mContext.getOrCreateTestableResources().getResources() + .getInteger(R.integer.config_powerPressCode)).thenReturn(testVendorPowerPressCode); + + client.onError(FINGERPRINT_ERROR_VENDOR, testVendorPowerPressCode); + + verify(mClientMonitorCallbackConverter).onError(anyInt(), anyInt(), + eq(BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED), anyInt()); + } + private void showHideOverlay(Consumer<FingerprintAuthenticationClient> block) throws RemoteException { final FingerprintAuthenticationClient client = createClient(); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java index 837b55397416..7e29a768db4a 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java @@ -16,7 +16,7 @@ package com.android.server.biometrics.sensors.fingerprint.aidl; -import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED; +import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR; import static com.google.common.truth.Truth.assertThat; @@ -28,10 +28,10 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.same; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.biometrics.common.OperationContext; import android.hardware.biometrics.fingerprint.ISession; import android.hardware.biometrics.fingerprint.PointerContext; @@ -48,6 +48,7 @@ import android.testing.TestableContext; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.internal.R; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; import com.android.server.biometrics.log.CallbackWithProbe; @@ -66,7 +67,6 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import java.util.ArrayList; import java.util.function.Consumer; @Presubmit @@ -258,11 +258,16 @@ public class FingerprintEnrollClientTest { @Test public void testPowerPressForwardsAcquireMessage() throws RemoteException { final FingerprintEnrollClient client = createClient(); - client.start(mCallback); - client.onPowerPressed(); + final int testVendorPowerPressCode = 1; + when(mContext.getOrCreateTestableResources().getResources() + .getBoolean(R.bool.config_powerPressMapping)).thenReturn(true); + when(mContext.getOrCreateTestableResources().getResources() + .getInteger(R.integer.config_powerPressCode)).thenReturn(testVendorPowerPressCode); + + client.onAcquired(FINGERPRINT_ACQUIRED_VENDOR, testVendorPowerPressCode); verify(mClientMonitorCallbackConverter).onAcquired(anyInt(), - eq(FINGERPRINT_ACQUIRED_POWER_PRESSED), anyInt()); + eq(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED), anyInt()); } private void showHideOverlay(Consumer<FingerprintEnrollClient> block) diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java index d1fbc1e50e83..8f70617a66ea 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -158,6 +158,8 @@ public final class DisplayDeviceConfigTest { assertEquals(90, mDisplayDeviceConfig.getDefaultHighBlockingZoneRefreshRate()); assertEquals(85, mDisplayDeviceConfig.getDefaultPeakRefreshRate()); assertEquals(45, mDisplayDeviceConfig.getDefaultRefreshRate()); + assertEquals(82, mDisplayDeviceConfig.getDefaultRefreshRateInHbmHdr()); + assertEquals(83, mDisplayDeviceConfig.getDefaultRefreshRateInHbmSunlight()); assertArrayEquals(new int[]{45, 55}, mDisplayDeviceConfig.getLowDisplayBrightnessThresholds()); assertArrayEquals(new int[]{50, 60}, @@ -465,6 +467,8 @@ public final class DisplayDeviceConfigTest { + "<refreshRate>\n" + "<defaultRefreshRate>45</defaultRefreshRate>\n" + "<defaultPeakRefreshRate>85</defaultPeakRefreshRate>\n" + + "<defaultRefreshRateInHbmHdr>82</defaultRefreshRateInHbmHdr>\n" + + "<defaultRefreshRateInHbmSunlight>83</defaultRefreshRateInHbmSunlight>\n" + "<lowerBlockingZoneConfigs>\n" + "<defaultRefreshRate>75</defaultRefreshRate>\n" + "<blockingZoneThreshold>\n" diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java index 303a370b0ba9..1ef11974292b 100644 --- a/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java @@ -99,7 +99,24 @@ public class DreamControllerTest { mLooper.dispatchAll(); // Verify that dream service is called to attach. - verify(mIDreamService).attach(eq(mToken), eq(false) /*doze*/, any()); + verify(mIDreamService).attach(eq(mToken), eq(false) /*doze*/, + eq(false) /*preview*/, any()); + } + + @Test + public void startDream_attachOnServiceConnectedInPreviewMode() throws RemoteException { + // Call dream controller to start dreaming. + mDreamController.startDream(mToken, mDreamName, true /*isPreview*/, false /*doze*/, + 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); + + // Mock service connected. + final ServiceConnection serviceConnection = captureServiceConnection(); + serviceConnection.onServiceConnected(mDreamName, mIBinder); + mLooper.dispatchAll(); + + // Verify that dream service is called to attach. + verify(mIDreamService).attach(eq(mToken), eq(false) /*doze*/, + eq(true) /*preview*/, any()); } @Test @@ -129,7 +146,7 @@ public class DreamControllerTest { // Mock second dream started. verify(newDreamService).attach(eq(newToken), eq(false) /*doze*/, - mRemoteCallbackCaptor.capture()); + eq(false) /*preview*/, mRemoteCallbackCaptor.capture()); mRemoteCallbackCaptor.getValue().sendResult(null /*data*/); mLooper.dispatchAll(); diff --git a/tests/testables/src/android/testing/TestableSettingsProvider.java b/tests/testables/src/android/testing/TestableSettingsProvider.java index fd92c657cb2e..c6f18fd453c5 100644 --- a/tests/testables/src/android/testing/TestableSettingsProvider.java +++ b/tests/testables/src/android/testing/TestableSettingsProvider.java @@ -49,14 +49,15 @@ public class TestableSettingsProvider extends MockContentProvider { } void clearValuesAndCheck(Context context) { - int userId = UserHandle.myUserId(); - mValues.put(key("global", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY); - mValues.put(key("secure", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY); - mValues.put(key("system", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY); - + // Ensure we swapped over to use TestableSettingsProvider Settings.Global.clearProviderForTest(); Settings.Secure.clearProviderForTest(); Settings.System.clearProviderForTest(); + + // putString will eventually invoking the mocked call() method and update mValues + Settings.Global.putString(context.getContentResolver(), MY_UNIQUE_KEY, MY_UNIQUE_KEY); + Settings.Secure.putString(context.getContentResolver(), MY_UNIQUE_KEY, MY_UNIQUE_KEY); + Settings.System.putString(context.getContentResolver(), MY_UNIQUE_KEY, MY_UNIQUE_KEY); // Verify that if any test is using TestableContext, they all have the correct settings // provider. assertEquals("Incorrect settings provider, test using incorrect Context?", MY_UNIQUE_KEY, |