diff options
859 files changed, 14513 insertions, 7398 deletions
diff --git a/Android.bp b/Android.bp index 9d8c8a69fc18..9d3b64d7335b 100644 --- a/Android.bp +++ b/Android.bp @@ -529,11 +529,7 @@ java_library { ], }, jarjar_prefix: "com.android.internal.hidden_from_bootclasspath", - - jarjar_shards: select(release_flag("RELEASE_USE_SHARDED_JARJAR_ON_FRAMEWORK_MINUS_APEX"), { - true: "10", - default: "1", - }), + jarjar_shards: "10", } java_library { diff --git a/core/api/current.txt b/core/api/current.txt index e0fc9590f9f7..6964866db7f3 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -45145,7 +45145,7 @@ package android.telephony { field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool"; field public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL = "show_ims_registration_status_bool"; field public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool"; - field @FlaggedApi("com.android.internal.telephony.flags.hide_roaming_icon") public static final String KEY_SHOW_ROAMING_INDICATOR_BOOL = "show_roaming_indicator_bool"; + field public static final String KEY_SHOW_ROAMING_INDICATOR_BOOL = "show_roaming_indicator_bool"; field public static final String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL = "show_signal_strength_in_sim_status_bool"; field public static final String KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL = "show_video_call_charges_alert_dialog_bool"; field public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL = "show_wfc_location_privacy_policy_bool"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 15ae79e34061..937a9ffaf210 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2224,7 +2224,7 @@ package android.app.contentsuggestions { package android.app.contextualsearch { - @FlaggedApi("android.app.contextualsearch.flags.enable_service") public final class CallbackToken implements android.os.Parcelable { + public final class CallbackToken implements android.os.Parcelable { ctor public CallbackToken(); method public int describeContents(); method public void getContextualSearchState(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.app.contextualsearch.ContextualSearchState,java.lang.Throwable>); @@ -2232,7 +2232,7 @@ package android.app.contextualsearch { field @NonNull public static final android.os.Parcelable.Creator<android.app.contextualsearch.CallbackToken> CREATOR; } - @FlaggedApi("android.app.contextualsearch.flags.enable_service") public final class ContextualSearchManager { + public final class ContextualSearchManager { method @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH) public void startContextualSearch(int); field public static final String ACTION_LAUNCH_CONTEXTUAL_SEARCH = "android.app.contextualsearch.action.LAUNCH_CONTEXTUAL_SEARCH"; field public static final int ENTRYPOINT_LONG_PRESS_HOME = 2; // 0x2 @@ -2250,7 +2250,7 @@ package android.app.contextualsearch { field public static final String EXTRA_VISIBLE_PACKAGE_NAMES = "android.app.contextualsearch.extra.VISIBLE_PACKAGE_NAMES"; } - @FlaggedApi("android.app.contextualsearch.flags.enable_service") public final class ContextualSearchState implements android.os.Parcelable { + public final class ContextualSearchState implements android.os.Parcelable { ctor public ContextualSearchState(@Nullable android.app.assist.AssistStructure, @Nullable android.app.assist.AssistContent, @NonNull android.os.Bundle); method public int describeContents(); method @Nullable public android.app.assist.AssistContent getContent(); @@ -3774,7 +3774,7 @@ package android.content { field public static final String CLOUDSEARCH_SERVICE = "cloudsearch"; field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions"; field public static final String CONTEXTHUB_SERVICE = "contexthub"; - field @FlaggedApi("android.app.contextualsearch.flags.enable_service") public static final String CONTEXTUAL_SEARCH_SERVICE = "contextual_search"; + field public static final String CONTEXTUAL_SEARCH_SERVICE = "contextual_search"; field @FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled") public static final String ECM_ENHANCED_CONFIRMATION_SERVICE = "ecm_enhanced_confirmation"; field public static final String ETHERNET_SERVICE = "ethernet"; field public static final String EUICC_CARD_SERVICE = "euicc_card"; @@ -15450,6 +15450,8 @@ package android.telephony { field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64 field public static final int DESTINATION_OUT_OF_ORDER = 27; // 0x1b field @FlaggedApi("com.android.internal.telephony.flags.use_oem_domain_selection_service") public static final int EMERGENCY_PERM_FAILURE = 326; // 0x146 + field @FlaggedApi("com.android.internal.telephony.flags.add_ims_redial_codes_for_emergency_calls") public static final int EMERGENCY_REDIAL_ON_IMS = 3001; // 0xbb9 + field @FlaggedApi("com.android.internal.telephony.flags.add_ims_redial_codes_for_emergency_calls") public static final int EMERGENCY_REDIAL_ON_VOWIFI = 3002; // 0xbba field @FlaggedApi("com.android.internal.telephony.flags.use_oem_domain_selection_service") public static final int EMERGENCY_TEMP_FAILURE = 325; // 0x145 field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff field public static final int FACILITY_REJECTED = 29; // 0x1d diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 0126db70296c..f06bd48a8cd8 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -809,7 +809,7 @@ package android.app.contentsuggestions { package android.app.contextualsearch { - @FlaggedApi("android.app.contextualsearch.flags.enable_service") public final class CallbackToken implements android.os.Parcelable { + public final class CallbackToken implements android.os.Parcelable { method @NonNull public android.os.IBinder getToken(); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2cfba4b8468f..7b9ec4a7821e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -7061,7 +7061,7 @@ public final class ActivityThread extends ClientTransactionHandler Slog.w(TAG, "Low overhead tracing feature is not enabled"); break; } - VMDebug.startLowOverheadTrace(); + VMDebug.startLowOverheadTraceForAllMethods(); break; default: try { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index fbe5b9449b00..35308ee43dea 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -4393,6 +4393,9 @@ public class Notification implements Parcelable */ @Nullable public Pair<RemoteInput, Action> findRemoteInputActionPair(boolean requiresFreeform) { + if (isPromotedOngoing()) { + return null; + } if (actions == null) { return null; } @@ -6454,6 +6457,11 @@ public class Notification implements Parcelable if (mActions == null) return Collections.emptyList(); List<Notification.Action> standardActions = new ArrayList<>(); for (Notification.Action action : mActions) { + // Actions with RemoteInput are ignored for RONs. + if (mN.isPromotedOngoing() + && hasValidRemoteInput(action)) { + continue; + } if (!action.isContextual()) { standardActions.add(action); } @@ -11932,7 +11940,7 @@ public class Notification implements Parcelable } /** - * Finds steps and points fill color with sufficient contrast over bg (1.3:1) that + * Finds steps and points fill color with sufficient contrast over bg (3:1) that * has the same hue as the original color, but is lightened or darkened depending on * whether the background is dark or light. * @@ -11945,7 +11953,7 @@ public class Notification implements Parcelable return Builder.ensureColorContrast( Color.alpha(color) == 0 ? defaultColor : color, bg, - 1.3); + 3); } /** diff --git a/core/java/android/app/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java index a731e5085466..6fd8db995368 100644 --- a/core/java/android/app/appfunctions/AppFunctionManager.java +++ b/core/java/android/app/appfunctions/AppFunctionManager.java @@ -42,12 +42,13 @@ import java.util.Objects; import java.util.concurrent.Executor; /** - * Provides access to app functions. + * Provides access to App Functions. App Functions is currently a + * beta/experimental preview feature. * * <p>An app function is a piece of functionality that apps expose to the system for cross-app * orchestration. * - * <p>**Building App Functions:** + * <h3>Building App Functions</h3> * * <p>Most developers should build app functions through the AppFunctions SDK. This SDK library * offers a more convenient and type-safe way to build app functions. The SDK provides predefined @@ -56,7 +57,7 @@ import java.util.concurrent.Executor; * these data classes into {@link ExecuteAppFunctionRequest#getParameters()} and {@link * ExecuteAppFunctionResponse#getResultDocument()}. * - * <p>**Discovering App Functions:** + * <h3>Discovering App Functions</h3> * * <p>When there is a package change or the device starts up, the metadata of available functions is * indexed on-device by {@link AppSearchManager}. AppSearch stores the indexed information as an @@ -66,7 +67,7 @@ import java.util.concurrent.Executor; * document is based on the packages that have visibility to the app providing the app functions. * AppFunction SDK provides a convenient way to achieve this and is the preferred method. * - * <p>**Executing App Functions:** + * <h3>Executing App Functions</h3> * * <p>To execute an app function, the caller app can retrieve the {@code functionIdentifier} from * the {@code AppFunctionStaticMetadata} document and use it to build an {@link @@ -76,7 +77,7 @@ import java.util.concurrent.Executor; * apps. An app can always execute its own app functions and doesn't need these permissions. * AppFunction SDK provides a convenient way to achieve this and is the preferred method. * - * <p>**Example:** + * <h3>Example</h3> * * <p>An assistant app is trying to fulfill the user request "Save XYZ into my note". The assistant * app should first list all available app functions as {@code AppFunctionStaticMetadata} documents diff --git a/core/java/android/app/appfunctions/OWNERS b/core/java/android/app/appfunctions/OWNERS index 6a69e15d00dd..822242de1a81 100644 --- a/core/java/android/app/appfunctions/OWNERS +++ b/core/java/android/app/appfunctions/OWNERS @@ -5,3 +5,4 @@ tonymak@google.com mingweiliao@google.com anothermark@google.com utkarshnigam@google.com +yaraabdullatif@google.com diff --git a/core/java/android/app/contextualsearch/CallbackToken.java b/core/java/android/app/contextualsearch/CallbackToken.java index 94cdc73fcd1d..c0ea1cd3a9de 100644 --- a/core/java/android/app/contextualsearch/CallbackToken.java +++ b/core/java/android/app/contextualsearch/CallbackToken.java @@ -44,7 +44,6 @@ import java.util.concurrent.Executor; * * @hide */ -@FlaggedApi(Flags.FLAG_ENABLE_SERVICE) @SystemApi public final class CallbackToken implements Parcelable { private static final boolean DEBUG = true; diff --git a/core/java/android/app/contextualsearch/ContextualSearchManager.java b/core/java/android/app/contextualsearch/ContextualSearchManager.java index ad43f271a910..2ce431dcb32d 100644 --- a/core/java/android/app/contextualsearch/ContextualSearchManager.java +++ b/core/java/android/app/contextualsearch/ContextualSearchManager.java @@ -43,7 +43,6 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @SystemApi -@FlaggedApi(Flags.FLAG_ENABLE_SERVICE) public final class ContextualSearchManager { /** diff --git a/core/java/android/app/contextualsearch/ContextualSearchState.java b/core/java/android/app/contextualsearch/ContextualSearchState.java index f01ae55d05b6..e1731bf525bf 100644 --- a/core/java/android/app/contextualsearch/ContextualSearchState.java +++ b/core/java/android/app/contextualsearch/ContextualSearchState.java @@ -38,7 +38,6 @@ import androidx.annotation.NonNull; * * @hide */ -@FlaggedApi(Flags.FLAG_ENABLE_SERVICE) @SystemApi public final class ContextualSearchState implements Parcelable { private final @NonNull Bundle mExtras; diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index a126363237b8..efcaa0ea6f07 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -2722,10 +2722,10 @@ public abstract class ContentResolver implements ContentInterface { /** @hide - designated user version */ @UnsupportedAppUsage - public final void registerContentObserver(Uri uri, boolean notifyForDescendents, + public final void registerContentObserver(Uri uri, boolean notifyForDescendants, ContentObserver observer, @UserIdInt int userHandle) { try { - getContentService().registerContentObserver(uri, notifyForDescendents, + getContentService().registerContentObserver(uri, notifyForDescendants, observer.getContentObserver(), userHandle, mTargetSdkVersion); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 7abf5600d659..8d54673df74c 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5593,7 +5593,6 @@ public abstract class Context { * @hide * @see #getSystemService(String) */ - @FlaggedApi(android.app.contextualsearch.flags.Flags.FLAG_ENABLE_SERVICE) @SystemApi public static final String CONTEXTUAL_SEARCH_SERVICE = "contextual_search"; diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java index 82663849f316..74da62c85ed2 100644 --- a/core/java/android/content/pm/RegisteredServicesCache.java +++ b/core/java/android/content/pm/RegisteredServicesCache.java @@ -527,13 +527,14 @@ public abstract class RegisteredServicesCache<V> { lastUpdateTime = packageInfo.lastUpdateTime; } catch (NameNotFoundException | SecurityException e) { Slog.d(TAG, "Fail to get the PackageInfo in generateServicesMap: " + e); - continue; } - ServiceInfo<V> serviceInfo = getServiceInfoFromServiceCache(componentName, - lastUpdateTime); - if (serviceInfo != null) { - serviceInfos.add(serviceInfo); - continue; + if (lastUpdateTime >= 0) { + ServiceInfo<V> serviceInfo = getServiceInfoFromServiceCache(componentName, + lastUpdateTime); + if (serviceInfo != null) { + serviceInfos.add(serviceInfo); + continue; + } } } try { diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig index 4a579a4c0e85..4e6fb8d3a8e7 100644 --- a/core/java/android/content/pm/multiuser.aconfig +++ b/core/java/android/content/pm/multiuser.aconfig @@ -500,6 +500,16 @@ flag { } flag { + name: "get_user_switchability_permission" + namespace: "multiuser" + description: "Update permissions for getUserSwitchability" + bug: "390458180" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "restrict_quiet_mode_credential_bug_fix_to_managed_profiles" namespace: "profile_experiences" description: "Use user states to check the state of quiet mode for managed profiles only" diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 53813012b4b3..71d0a04760ac 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -541,9 +541,9 @@ public class ApkLiteParseUtils { case TAG_USES_SDK_LIBRARY: String usesSdkLibName = parser.getAttributeValue( ANDROID_RES_NAMESPACE, "name"); - // TODO(b/379219371): Due to a bug in bundletool, some apps can use - // versionMajor as string. Until it is resolved, we are adding a - // workaround here. + // TODO(b/391604666): Due to a bug in bundletool, old apps could be + // using versionMajor as string. Do not remove this workaround until + // b/391604666 is resolved. String usesSdkLibVersionMajorString = parser.getAttributeValue( ANDROID_RES_NAMESPACE, "versionMajor"); long usesSdkLibVersionMajor = XmlUtils.convertValueToInt( diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java index 7361d4f6b882..063f5545dd71 100644 --- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java +++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java @@ -44,7 +44,7 @@ public class AmbientDisplayConfiguration { private final Context mContext; private final boolean mAlwaysOnByDefault; private final boolean mPickupGestureEnabledByDefault; - private final boolean mScreenOffUdfpsEnabledByDefault; + private final boolean mScreenOffUdfpsAvailable; /** Copied from android.provider.Settings.Secure since these keys are hidden. */ private static final String[] DOZE_SETTINGS = { @@ -72,7 +72,7 @@ public class AmbientDisplayConfiguration { mAlwaysOnByDefault = mContext.getResources().getBoolean(R.bool.config_dozeAlwaysOnEnabled); mPickupGestureEnabledByDefault = mContext.getResources().getBoolean(R.bool.config_dozePickupGestureEnabled); - mScreenOffUdfpsEnabledByDefault = + mScreenOffUdfpsAvailable = mContext.getResources().getBoolean(R.bool.config_screen_off_udfps_enabled); } @@ -152,7 +152,8 @@ public class AmbientDisplayConfiguration { /** @hide */ public boolean screenOffUdfpsEnabled(int user) { return !TextUtils.isEmpty(udfpsLongPressSensorType()) - && ((mScreenOffUdfpsEnabledByDefault && Flags.screenOffUnlockUdfps()) + && ((mScreenOffUdfpsAvailable && Flags.screenOffUnlockUdfps()) + && mContext.getResources().getBoolean(R.bool.config_screen_off_udfps_default_on) ? boolSettingDefaultOn(SCREEN_OFF_UNLOCK_UDFPS_ENABLED, user) : boolSettingDefaultOff(SCREEN_OFF_UNLOCK_UDFPS_ENABLED, user)); } diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index d273ddb15cc4..343e4b5668c0 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -475,6 +475,12 @@ public abstract class DisplayManagerInternal { */ public abstract boolean isDisplayReadyForMirroring(int displayId); + /** + * Called by {@link com.android.server.display.DisplayBackupHelper} when backup files were + * restored and are ready to be reloaded. + */ + public abstract void reloadTopologies(int userId); + /** * Used by the window manager to override the per-display screen brightness based on the diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index 62126963cba4..79323bf2f2f7 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -225,3 +225,13 @@ flag { description: "Removes modifiers from the original key event that activated the fallback, ensuring that only the intended fallback event is sent." bug: "382545048" } + +flag { + name: "abort_slow_multi_press" + namespace: "wear_frameworks" + description: "If a press that's a part of a multipress takes too long, the multipress gesture will be cancelled." + bug: "370095426" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java index 38be8d9f772d..019ba0045916 100644 --- a/core/java/android/inputmethodservice/NavigationBarController.java +++ b/core/java/android/inputmethodservice/NavigationBarController.java @@ -16,6 +16,9 @@ package android.inputmethodservice; +import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; +import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; +import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN; import static android.view.WindowInsets.Type.captionBar; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; @@ -23,7 +26,6 @@ import android.animation.ValueAnimator; import android.annotation.FloatRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.StatusBarManager; import android.graphics.Color; import android.graphics.Insets; import android.graphics.Rect; @@ -241,10 +243,9 @@ final class NavigationBarController { if (navigationBarView != null) { // TODO(b/213337792): Support InputMethodService#setBackDisposition(). // TODO(b/213337792): Set NAVIGATION_HINT_IME_SHOWN only when necessary. - final int hints = StatusBarManager.NAVIGATION_HINT_BACK_ALT + final int hints = NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN | (mShouldShowImeSwitcherWhenImeIsShown - ? StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN - : 0); + ? NAVIGATION_HINT_IME_SWITCHER_SHOWN : 0); navigationBarView.setNavigationIconHints(hints); navigationBarView.prepareNavButtons(this); } @@ -512,13 +513,14 @@ final class NavigationBarController { } final NavigationBarView navigationBarView = mNavigationBarFrame.findViewByPredicate( NavigationBarView.class::isInstance); - if (navigationBarView == null) { - return; + if (navigationBarView != null) { + // TODO(b/213337792): Support InputMethodService#setBackDisposition(). + // TODO(b/213337792): Set NAVIGATION_HINT_IME_SHOWN only when necessary. + final int hints = NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN + | (mShouldShowImeSwitcherWhenImeIsShown + ? NAVIGATION_HINT_IME_SWITCHER_SHOWN : 0); + navigationBarView.setNavigationIconHints(hints); } - final int hints = StatusBarManager.NAVIGATION_HINT_BACK_ALT - | (shouldShowImeSwitcherWhenImeIsShown - ? StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN : 0); - navigationBarView.setNavigationIconHints(hints); } else { uninstallNavigationBarFrameIfNecessary(); } diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java index 209f323d7b34..e7e46a9482c8 100644 --- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java +++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java @@ -290,7 +290,7 @@ public final class NavigationBarView extends FrameLayout { final boolean oldBackAlt = (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0; if (newBackAlt != oldBackAlt) { - //onImeVisibilityChanged(newBackAlt); + //onBackAltChanged(newBackAlt); } if (DEBUG) { diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index 1041041b2a27..1cf293d46350 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -45,8 +45,7 @@ import java.util.function.BiFunction; * {@link PersistableBundle} subclass. */ @android.ravenwood.annotation.RavenwoodKeepWholeClass -@SuppressWarnings("HiddenSuperclass") -public class BaseBundle implements Parcel.ClassLoaderProvider { +public class BaseBundle { /** @hide */ protected static final String TAG = "Bundle"; static final boolean DEBUG = false; @@ -300,9 +299,8 @@ public class BaseBundle implements Parcel.ClassLoaderProvider { /** * Return the ClassLoader currently associated with this Bundle. - * @hide */ - public ClassLoader getClassLoader() { + ClassLoader getClassLoader() { return mClassLoader; } @@ -416,9 +414,6 @@ public class BaseBundle implements Parcel.ClassLoaderProvider { if ((mFlags & Bundle.FLAG_VERIFY_TOKENS_PRESENT) != 0) { Intent.maybeMarkAsMissingCreatorToken(object); } - } else if (object instanceof Bundle) { - Bundle bundle = (Bundle) object; - bundle.setClassLoaderSameAsContainerBundleWhenRetrievedFirstTime(this); } return (clazz != null) ? clazz.cast(object) : (T) object; } @@ -492,7 +487,7 @@ public class BaseBundle implements Parcel.ClassLoaderProvider { int[] numLazyValues = new int[]{0}; try { parcelledData.readArrayMap(map, count, !parcelledByNative, - /* lazy */ ownsParcel, this, numLazyValues); + /* lazy */ ownsParcel, mClassLoader, numLazyValues); } catch (BadParcelableException e) { if (sShouldDefuse) { Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e); diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index 55bfd451d97a..819d58d9f059 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -141,8 +141,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { STRIPPED.putInt("STRIPPED", 1); } - private boolean isFirstRetrievedFromABundle = false; - /** * Constructs a new, empty Bundle. */ @@ -1022,9 +1020,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { return null; } try { - Bundle bundle = (Bundle) o; - bundle.setClassLoaderSameAsContainerBundleWhenRetrievedFirstTime(this); - return bundle; + return (Bundle) o; } catch (ClassCastException e) { typeWarning(key, o, "Bundle", e); return null; @@ -1032,21 +1028,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** - * Set the ClassLoader of a bundle to its container bundle. This is necessary so that when a - * bundle's ClassLoader is changed, it can be propagated to its children. Do this only when it - * is retrieved from the container bundle first time though. Once it is accessed outside of its - * container, its ClassLoader should no longer be changed by its container anymore. - * - * @param containerBundle the bundle this bundle is retrieved from. - */ - void setClassLoaderSameAsContainerBundleWhenRetrievedFirstTime(BaseBundle containerBundle) { - if (!isFirstRetrievedFromABundle) { - setClassLoader(containerBundle.getClassLoader()); - isFirstRetrievedFromABundle = true; - } - } - - /** * Returns the value associated with the given key, or {@code null} if * no mapping of the desired type exists for the given key or a {@code null} * value is explicitly associated with the key. diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java index 3026609ed5cb..50b621c46778 100644 --- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java +++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java @@ -1474,54 +1474,11 @@ public final class MessageQueue { Iterator<MessageNode> queueIter = mPriorityQueue.iterator(); MessageNode queueNode = iterateNext(queueIter); - if (queueNode != null && queueNode.isBarrier()) { - long now = SystemClock.uptimeMillis(); - - /* Look for a deliverable async node. If one exists we are not blocked. */ - Iterator<MessageNode> asyncQueueIter = mAsyncPriorityQueue.iterator(); - MessageNode asyncNode = iterateNext(asyncQueueIter); - if (asyncNode != null && now >= asyncNode.getWhen()) { - return false; - } - /* - * Look for a deliverable sync node. In this case, if one exists we are blocked - * since the barrier prevents delivery of the Message. - */ - while (queueNode != null && queueNode.isBarrier()) { - queueNode = iterateNext(queueIter); - } - if (queueNode != null && now >= queueNode.getWhen()) { - return true; - } - } + return (queueNode != null && queueNode.isBarrier()); } else { Message msg = mMessages; - if (msg != null && msg.target == null) { - Message iter = msg; - /* Look for a deliverable async node */ - do { - iter = iter.next; - } while (iter != null && !iter.isAsynchronous()); - - long now = SystemClock.uptimeMillis(); - if (iter != null && now >= iter.when) { - return false; - } - /* - * Look for a deliverable sync node. In this case, if one exists we are blocked - * since the barrier prevents delivery of the Message. - */ - iter = msg; - do { - iter = iter.next; - } while (iter != null && (iter.target == null || iter.isAsynchronous())); - - if (iter != null && now >= iter.when) { - return true; - } - } + return msg != null && msg.target == null; } - return false; } private static final class MatchHandlerWhatAndObject extends MessageCompare { diff --git a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java index d7d8e4199b33..80da487a1358 100644 --- a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java +++ b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java @@ -16,7 +16,6 @@ package android.os; -import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1122,27 +1121,7 @@ public final class MessageQueue { Iterator<MessageNode> queueIter = mPriorityQueue.iterator(); MessageNode queueNode = iterateNext(queueIter); - if (queueNode != null && queueNode.isBarrier()) { - long now = SystemClock.uptimeMillis(); - - /* Look for a deliverable async node. If one exists we are not blocked. */ - Iterator<MessageNode> asyncQueueIter = mAsyncPriorityQueue.iterator(); - MessageNode asyncNode = iterateNext(asyncQueueIter); - if (asyncNode != null && now >= asyncNode.getWhen()) { - return false; - } - /* - * Look for a deliverable sync node. In this case, if one exists we are blocked - * since the barrier prevents delivery of the Message. - */ - while (queueNode != null && queueNode.isBarrier()) { - queueNode = iterateNext(queueIter); - } - if (queueNode != null && now >= queueNode.getWhen()) { - return true; - } - } - return false; + return queueNode != null && queueNode.isBarrier(); } private StateNode getStateNode(StackNode node) { diff --git a/core/java/android/os/LegacyMessageQueue/MessageQueue.java b/core/java/android/os/LegacyMessageQueue/MessageQueue.java index d12d99a71251..cde2ba56fcba 100644 --- a/core/java/android/os/LegacyMessageQueue/MessageQueue.java +++ b/core/java/android/os/LegacyMessageQueue/MessageQueue.java @@ -820,33 +820,10 @@ public final class MessageQueue { */ boolean isBlockedOnSyncBarrier() { throwIfNotTest(); - Message msg = mMessages; - if (msg != null && msg.target == null) { - Message iter = msg; - /* Look for a deliverable async node */ - do { - iter = iter.next; - } while (iter != null && !iter.isAsynchronous()); - - long now = SystemClock.uptimeMillis(); - if (iter != null && now >= iter.when) { - return false; - } - /* - * Look for a deliverable sync node. In this case, if one exists we are blocked - * since the barrier prevents delivery of the Message. - */ - iter = msg; - do { - iter = iter.next; - } while (iter != null && (iter.target == null || iter.isAsynchronous())); - - if (iter != null && now >= iter.when) { - return true; - } - return false; + synchronized (this) { + Message msg = mMessages; + return msg != null && msg.target == null; } - return false; } boolean hasMessages(Handler h, int what, Object object) { diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index c6a63a7ef238..e58934746c14 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -50,7 +50,6 @@ import com.android.internal.util.ArrayUtils; import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; -import dalvik.annotation.optimization.NeverInline; import libcore.util.SneakyThrow; @@ -629,19 +628,6 @@ public final class Parcel { } } - @NeverInline - private void errorUsedWhileRecycling() { - String error = "Parcel used while recycled. " - + Log.getStackTraceString(new Throwable()) - + " Original recycle call (if DEBUG_RECYCLE): ", mStack; - Log.wtf(TAG, error); - // TODO(b/381155347): harder error - } - - private void assertNotRecycled() { - if (mRecycled) errorUsedWhileRecycling(); - } - /** * Set a {@link ReadWriteHelper}, which can be used to avoid having duplicate strings, for * example. @@ -1194,7 +1180,6 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeInt(int val) { - assertNotRecycled(); int err = nativeWriteInt(mNativePtr, val); if (err != OK) { nativeSignalExceptionForError(err); @@ -3297,7 +3282,6 @@ public final class Parcel { * Read an integer value from the parcel at the current dataPosition(). */ public final int readInt() { - assertNotRecycled(); return nativeReadInt(mNativePtr); } @@ -4639,9 +4623,11 @@ public final class Parcel { object = readValue(type, loader, clazz, itemTypes); int actual = dataPosition() - start; if (actual != length) { - Slog.wtfStack(TAG, - "Unparcelling of " + object + " of type " + Parcel.valueTypeToString(type) - + " consumed " + actual + " bytes, but " + length + " expected."); + String error = "Unparcelling of " + object + " of type " + + Parcel.valueTypeToString(type) + " consumed " + actual + + " bytes, but " + length + " expected."; + Slog.wtfStack(TAG, error); + throw new BadParcelableException(error); } } else { object = readValue(type, loader, clazz, itemTypes); @@ -4675,7 +4661,7 @@ public final class Parcel { * @hide */ @Nullable - private Object readLazyValue(@Nullable ClassLoaderProvider loaderProvider) { + public Object readLazyValue(@Nullable ClassLoader loader) { int start = dataPosition(); int type = readInt(); if (isLengthPrefixed(type)) { @@ -4686,17 +4672,12 @@ public final class Parcel { int end = MathUtils.addOrThrow(dataPosition(), objectLength); int valueLength = end - start; setDataPosition(end); - return new LazyValue(this, start, valueLength, type, loaderProvider); + return new LazyValue(this, start, valueLength, type, loader); } else { - return readValue(type, getClassLoader(loaderProvider), /* clazz */ null); + return readValue(type, loader, /* clazz */ null); } } - @Nullable - private static ClassLoader getClassLoader(@Nullable ClassLoaderProvider loaderProvider) { - return loaderProvider == null ? null : loaderProvider.getClassLoader(); - } - private static final class LazyValue implements BiFunction<Class<?>, Class<?>[], Object> { /** @@ -4710,12 +4691,7 @@ public final class Parcel { private final int mPosition; private final int mLength; private final int mType; - // this member is set when a bundle that includes a LazyValue is unparceled. But it is used - // when apply method is called. Between these 2 events, the bundle's ClassLoader could have - // changed. Let the bundle be a ClassLoaderProvider allows the bundle provides its current - // ClassLoader at the time apply method is called. - @NonNull - private final ClassLoaderProvider mLoaderProvider; + @Nullable private final ClassLoader mLoader; @Nullable private Object mObject; /** @@ -4726,13 +4702,12 @@ public final class Parcel { */ @Nullable private volatile Parcel mSource; - LazyValue(Parcel source, int position, int length, int type, - @NonNull ClassLoaderProvider loaderProvider) { + LazyValue(Parcel source, int position, int length, int type, @Nullable ClassLoader loader) { mSource = requireNonNull(source); mPosition = position; mLength = length; mType = type; - mLoaderProvider = loaderProvider; + mLoader = loader; } @Override @@ -4745,8 +4720,7 @@ public final class Parcel { int restore = source.dataPosition(); try { source.setDataPosition(mPosition); - mObject = source.readValue(mLoaderProvider.getClassLoader(), clazz, - itemTypes); + mObject = source.readValue(mLoader, clazz, itemTypes); } finally { source.setDataPosition(restore); } @@ -4819,8 +4793,7 @@ public final class Parcel { return Objects.equals(mObject, value.mObject); } // Better safely fail here since this could mean we get different objects. - if (!Objects.equals(mLoaderProvider.getClassLoader(), - value.mLoaderProvider.getClassLoader())) { + if (!Objects.equals(mLoader, value.mLoader)) { return false; } // Otherwise compare metadata prior to comparing payload. @@ -4834,24 +4807,10 @@ public final class Parcel { @Override public int hashCode() { // Accessing mSource first to provide memory barrier for mObject - return Objects.hash(mSource == null, mObject, mLoaderProvider.getClassLoader(), mType, - mLength); + return Objects.hash(mSource == null, mObject, mLoader, mType, mLength); } } - /** - * Provides a ClassLoader. - * @hide - */ - public interface ClassLoaderProvider { - /** - * Returns a ClassLoader. - * - * @return ClassLoader - */ - ClassLoader getClassLoader(); - } - /** Same as {@link #readValue(ClassLoader, Class, Class[])} without any item types. */ private <T> T readValue(int type, @Nullable ClassLoader loader, @Nullable Class<T> clazz) { // Avoids allocating Class[0] array @@ -5592,8 +5551,8 @@ public final class Parcel { } private void readArrayMapInternal(@NonNull ArrayMap<? super String, Object> outVal, - int size, @Nullable ClassLoaderProvider loaderProvider) { - readArrayMap(outVal, size, /* sorted */ true, /* lazy */ false, loaderProvider, null); + int size, @Nullable ClassLoader loader) { + readArrayMap(outVal, size, /* sorted */ true, /* lazy */ false, loader, null); } /** @@ -5607,12 +5566,11 @@ public final class Parcel { * @hide */ void readArrayMap(ArrayMap<? super String, Object> map, int size, boolean sorted, - boolean lazy, @Nullable ClassLoaderProvider loaderProvider, int[] lazyValueCount) { + boolean lazy, @Nullable ClassLoader loader, int[] lazyValueCount) { ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, size); while (size > 0) { String key = readString(); - Object value = (lazy) ? readLazyValue(loaderProvider) : readValue( - getClassLoader(loaderProvider)); + Object value = (lazy) ? readLazyValue(loader) : readValue(loader); if (value instanceof LazyValue) { lazyValueCount[0]++; } @@ -5633,12 +5591,12 @@ public final class Parcel { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void readArrayMap(@NonNull ArrayMap<? super String, Object> outVal, - @Nullable ClassLoaderProvider loaderProvider) { + @Nullable ClassLoader loader) { final int N = readInt(); if (N < 0) { return; } - readArrayMapInternal(outVal, N, loaderProvider); + readArrayMapInternal(outVal, N, loader); } /** diff --git a/core/java/android/os/TestLooperManager.java b/core/java/android/os/TestLooperManager.java index 289b98c9b1d4..d451109554fa 100644 --- a/core/java/android/os/TestLooperManager.java +++ b/core/java/android/os/TestLooperManager.java @@ -129,9 +129,6 @@ public class TestLooperManager { /** * Checks whether the Looper is currently blocked on a sync barrier. - * - * A Looper is blocked on a sync barrier if there is a Message in the Looper's - * queue that is ready for execution but is behind a sync barrier */ @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY) public boolean isBlockedOnSyncBarrier() { diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 08f68f1874e7..967f55ce7a88 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -30,6 +30,9 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SpecialUsers.CanBeALL; +import android.annotation.SpecialUsers.CanBeNULL; +import android.annotation.SpecialUsers.CannotBeSpecialUser; import android.annotation.StringDef; import android.annotation.SuppressAutoDoc; import android.annotation.SuppressLint; @@ -3913,7 +3916,8 @@ public class UserManager { android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) - public @NonNull UserProperties getUserProperties(@NonNull UserHandle userHandle) { + public @NonNull UserProperties getUserProperties( + @CannotBeSpecialUser @NonNull UserHandle userHandle) { final int userId = userHandle.getIdentifier(); if (userId < 0 && android.multiuser.Flags.fixGetUserPropertyCache()) { @@ -6811,7 +6815,7 @@ public class UserManager { */ @SystemApi public static final class EnforcingUser implements Parcelable { - private final @UserIdInt int userId; + private final @CanBeALL @CanBeNULL @UserIdInt int userId; private final @UserRestrictionSource int userRestrictionSource; /** @@ -6856,7 +6860,7 @@ public class UserManager { * * <p> Will be UserHandle.USER_NULL when restriction is set by the system. */ - public UserHandle getUserHandle() { + public @CanBeALL @CanBeNULL UserHandle getUserHandle() { return UserHandle.of(userId); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 2e231e3957c6..65c857a51b29 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11008,6 +11008,21 @@ public final class Settings { @Readable public static final String SHOW_NOTIFICATION_SNOOZE = "show_notification_snooze"; + /** + * Controls whether dual shade is enabled. This splits notifications and quick settings to + * have their own independently expandable/collapsible panels, appearing on either side of + * the large screen (including unfolded device) or sharing a space on a narrow screen + * (including a folded device). Both panels will now cover the screen only partially + * (wrapping their content), so a running app or the lockscreen will remain visible in the + * background. + * <p> + * Type: int (0 for false, 1 for true) + * + * @hide + */ + @android.provider.Settings.Readable + public static final String DUAL_SHADE = "dual_shade"; + /** * 1 if it is allowed to remove the primary GAIA account. 0 by default. * @hide @@ -13788,6 +13803,16 @@ public final class Settings { = "enable_freeform_support"; /** + * Whether to override the availability of the desktop experiences features on the + * device. With desktop experiences enabled, secondary displays can be used to run + * apps, in desktop mode by default. Otherwise they can only be used for mirroring. + * @hide + */ + @Readable + public static final String DEVELOPMENT_OVERRIDE_DESKTOP_EXPERIENCE_FEATURES = + "override_desktop_experience_features"; + + /** * Whether to override the availability of the desktop mode on the main display of the * device. If on, users can make move an app to the desktop, allowing a freeform windowing * experience. diff --git a/core/java/android/security/FileIntegrityManager.java b/core/java/android/security/FileIntegrityManager.java index 478435b1ac5e..9e02ecd19aee 100644 --- a/core/java/android/security/FileIntegrityManager.java +++ b/core/java/android/security/FileIntegrityManager.java @@ -170,11 +170,6 @@ public final class FileIntegrityManager { @Deprecated public boolean isAppSourceCertificateTrusted(@NonNull X509Certificate certificate) throws CertificateEncodingException { - try { - return mService.isAppSourceCertificateTrusted( - certificate.getEncoded(), mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return false; } } diff --git a/core/java/android/security/IFileIntegrityService.aidl b/core/java/android/security/IFileIntegrityService.aidl index ddb662ad42cb..c6def239d59a 100644 --- a/core/java/android/security/IFileIntegrityService.aidl +++ b/core/java/android/security/IFileIntegrityService.aidl @@ -25,7 +25,6 @@ import android.os.IInstalld; */ interface IFileIntegrityService { boolean isApkVeritySupported(); - boolean isAppSourceCertificateTrusted(in byte[] certificateBytes, in String packageName); IInstalld.IFsveritySetupAuthToken createAuthToken(in ParcelFileDescriptor authFd); diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java index a337ba2a57fb..e0d4ec1ca826 100644 --- a/core/java/android/text/style/TtsSpan.java +++ b/core/java/android/text/style/TtsSpan.java @@ -108,11 +108,13 @@ public class TtsSpan implements ParcelableSpan { /** * The text associated with this span is a time, consisting of a number of - * hours and minutes, specified with {@link #ARG_HOURS} and - * {@link #ARG_MINUTES}. + * hours, minutes, and seconds specified with {@link #ARG_HOURS}, {@link #ARG_MINUTES}, and + * {@link #ARG_SECONDS}. * Also accepts the arguments {@link #ARG_GENDER}, * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and - * {@link #ARG_CASE}. + * {@link #ARG_CASE}. This is different from {@link #TYPE_DURATION}. This should be used to + * convey a particular moment in time, such as a clock time, while {@link #TYPE_DURATION} should + * be used to convey an interval of time. */ public static final String TYPE_TIME = "android.type.time"; @@ -310,16 +312,18 @@ public class TtsSpan implements ParcelableSpan { public static final String ARG_UNIT = "android.arg.unit"; /** - * Argument used to specify the hours of a time. The hours should be - * provided as an integer in the range from 0 up to and including 24. - * Can be used with {@link #TYPE_TIME}. + * Argument used to specify the hours of a time or duration. The hours should be + * provided as an integer in the range from 0 up to and including 24 for + * {@link #TYPE_TIME}. + * Can be used with {@link #TYPE_TIME} or {@link #TYPE_DURATION}. */ public static final String ARG_HOURS = "android.arg.hours"; /** - * Argument used to specify the minutes of a time. The minutes should be - * provided as an integer in the range from 0 up to and including 59. - * Can be used with {@link #TYPE_TIME}. + * Argument used to specify the minutes of a time or duration. The minutes should be + * provided as an integer in the range from 0 up to and including 59 for + * {@link #TYPE_TIME}. + * Can be used with {@link #TYPE_TIME} or {@link #TYPE_DURATION}. */ public static final String ARG_MINUTES = "android.arg.minutes"; diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index f58baffb1367..2ec5dbc5612a 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -1146,6 +1146,14 @@ interface IWindowManager */ KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId); + /* + * Notifies about IME insets animation. + * + * @param running Indicates the insets animation state. + * @param animationType Indicates the {@link InsetsController.AnimationType} + */ + oneway void notifyImeInsetsAnimationStateChanged(boolean running, int animationType); + /** * Returns whether the display with {@code displayId} ignores orientation request. */ diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index c174fbe0bbcd..e097a0764512 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -214,9 +214,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation * Notifies when the state of running animation is changed. The state is either "running" or * "idle". * - * @param running {@code true} if there is any animation running; {@code false} otherwise. + * @param running {@code true} if the given insets types start running + * {@code false} otherwise. + * @param animationType {@link AnimationType} + * @param insetsTypes {@link Type}. */ - default void notifyAnimationRunningStateChanged(boolean running) {} + default void notifyAnimationRunningStateChanged(boolean running, + @AnimationType int animationType, @InsetsType int insetsTypes) { + } /** @see ViewRootImpl#isHandlingPointerEvent */ default boolean isHandlingPointerEvent() { @@ -744,9 +749,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final InsetsAnimationControlRunner runner = new InsetsResizeAnimationRunner( mFrame, mFromState, mToState, RESIZE_INTERPOLATOR, ANIMATION_DURATION_RESIZE, mTypes, InsetsController.this); - if (mRunningAnimations.isEmpty()) { - mHost.notifyAnimationRunningStateChanged(true); - } + mHost.notifyAnimationRunningStateChanged(true, + runner.getAnimationType(), mTypes); mRunningAnimations.add(new RunningAnimation(runner, runner.getAnimationType())); } }; @@ -1560,9 +1564,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } } ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_ANIMATION_RUNNING); - if (mRunningAnimations.isEmpty()) { - mHost.notifyAnimationRunningStateChanged(true); - } + mHost.notifyAnimationRunningStateChanged(true, animationType, types); mRunningAnimations.add(new RunningAnimation(runner, animationType)); if (DEBUG) Log.d(TAG, "Animation added to runner. useInsetsAnimationThread: " + useInsetsAnimationThread); @@ -1842,9 +1844,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation break; } } - if (mRunningAnimations.isEmpty()) { - mHost.notifyAnimationRunningStateChanged(false); - } + mHost.notifyAnimationRunningStateChanged( + false, control.getAnimationType(), removedTypes); onAnimationStateChanged(removedTypes, false /* running */); } diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java index 7f2f0e8863df..cfb4835a13f7 100644 --- a/core/java/android/view/InsetsSourceControl.java +++ b/core/java/android/view/InsetsSourceControl.java @@ -194,7 +194,7 @@ public class InsetsSourceControl implements Parcelable { } public void release(Consumer<SurfaceControl> surfaceReleaseConsumer) { - if (mLeash != null) { + if (mLeash != null && mLeash.isValid()) { surfaceReleaseConsumer.accept(mLeash); } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index cd8a85a66c1a..7c5b300e9d24 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -24,6 +24,7 @@ import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED; import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND; import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID; import static android.os.Trace.TRACE_TAG_VIEW; +import static android.service.autofill.Flags.improveFillDialogAconfig; import static android.util.SequenceUtils.getInitSeq; import static android.util.SequenceUtils.isIncomingSeqStale; import static android.view.Display.DEFAULT_DISPLAY; @@ -922,6 +923,8 @@ public final class ViewRootImpl implements ViewParent, private boolean mInsetsAnimationRunning; + private int mInsetsAnimatingTypes = 0; + private long mPreviousFrameDrawnTime = -1; // The largest view size percentage to the display size. Used on trace to collect metric. private float mLargestChildPercentage = 0.0f; @@ -2520,17 +2523,49 @@ public final class ViewRootImpl implements ViewParent, * Notify the when the running state of a insets animation changed. */ @VisibleForTesting - public void notifyInsetsAnimationRunningStateChanged(boolean running) { + public void notifyInsetsAnimationRunningStateChanged(boolean running, + @InsetsController.AnimationType int animationType, + @InsetsType int insetsTypes) { + @InsetsType int previousInsetsType = mInsetsAnimatingTypes; + // If improveFillDialogAconfig is disabled, we notify WindowSession of all the updates we + // receive here + boolean notifyWindowSession = !improveFillDialogAconfig(); + if (running) { + mInsetsAnimatingTypes |= insetsTypes; + } else { + mInsetsAnimatingTypes &= ~insetsTypes; + } if (sToolkitSetFrameRateReadOnlyFlagValue) { - if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.instant(Trace.TRACE_TAG_VIEW, - TextUtils.formatSimple("notifyInsetsAnimationRunningStateChanged(%s)", - Boolean.toString(running))); - } mInsetsAnimationRunning = running; - try { - mWindowSession.notifyInsetsAnimationRunningStateChanged(mWindow, running); - } catch (RemoteException e) { + // If improveFillDialogAconfig is enabled, we need to confirm other animations aren't + // running to maintain the existing behavior. System server were notified previously + // only when animation started running or stopped when there were no running animations. + if (improveFillDialogAconfig()) { + if ((previousInsetsType == 0 && mInsetsAnimatingTypes != 0) + || (previousInsetsType != 0 && mInsetsAnimatingTypes == 0)) { + notifyWindowSession = true; + } + } + if (notifyWindowSession) { + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + Trace.instant(Trace.TRACE_TAG_VIEW, + TextUtils.formatSimple("notifyInsetsAnimationRunningStateChanged(%s)", + Boolean.toString(running))); + } + try { + mWindowSession.notifyInsetsAnimationRunningStateChanged(mWindow, running); + } catch (RemoteException e) { + } + } + } + if (improveFillDialogAconfig()) { + // Update WindowManager for ImeAnimation + if ((insetsTypes & WindowInsets.Type.ime()) != 0) { + try { + WindowManagerGlobal.getWindowManagerService() + .notifyImeInsetsAnimationStateChanged(running, animationType); + } catch (RemoteException e) { + } } } } diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java index 889acca4b8b1..f1666dbebd7b 100644 --- a/core/java/android/view/ViewRootInsetsControllerHost.java +++ b/core/java/android/view/ViewRootInsetsControllerHost.java @@ -275,9 +275,12 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { } @Override - public void notifyAnimationRunningStateChanged(boolean running) { + public void notifyAnimationRunningStateChanged(boolean running, + @InsetsController.AnimationType int animationType, + @WindowInsets.Type.InsetsType int insetsTypes) { if (mViewRoot != null) { - mViewRoot.notifyInsetsAnimationRunningStateChanged(running); + mViewRoot.notifyInsetsAnimationRunningStateChanged( + running, animationType, insetsTypes); } } diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java index 206e47f13890..0814e23eea87 100644 --- a/core/java/android/view/autofill/AutofillFeatureFlags.java +++ b/core/java/android/view/autofill/AutofillFeatureFlags.java @@ -21,6 +21,7 @@ import static android.service.autofill.Flags.improveFillDialogAconfig; import android.annotation.SuppressLint; import android.annotation.TestApi; import android.provider.DeviceConfig; +import android.service.autofill.Flags; import android.text.TextUtils; import android.util.ArraySet; import android.view.View; @@ -348,6 +349,14 @@ public class AutofillFeatureFlags { // END AUTOFILL REMOVE PRE_TRIGGER FLAGS /** + * Whether per Session FillEventHistory is enabled. + * + * @hide + */ + public static final String DEVICE_CONFIG_SESSION_FILL_EVENT_HISTORY = + "session_fill_event_history"; + + /** * Define the max input length for autofill to show suggesiton UI * * E.g. if flag is set to 3, autofill will only show suggestions when user inputs less than 3 @@ -409,6 +418,13 @@ public class AutofillFeatureFlags { // END AUTOFILL REMOVE PRE_TRIGGER FLAGS DEFAULTS /** + * Default for whether per Session FillEventHistory is enabled + * + * @hide + */ + public static final boolean DEFAULT_SESSION_FILL_EVENT_HISTORY_ENABLED = false; + + /** * @hide */ public static final int DEFAULT_MAX_INPUT_LENGTH_FOR_AUTOFILL = 3; @@ -697,4 +713,20 @@ public class AutofillFeatureFlags { DEVICE_CONFIG_FILL_DIALOG_MIN_WAIT_AFTER_IME_ANIMATION_END_MS, DEFAULT_FILL_DIALOG_MIN_WAIT_AFTER_IME_ANIMATION_END_MS); } + + /** + * Whether tracking FillEventHistory per Session is enabled + * + * @hide + */ + public static boolean isMultipleFillEventHistoryEnabled() { + if (!Flags.multipleFillHistory()) { + return false; + } + + return DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_AUTOFILL, + DEVICE_CONFIG_SESSION_FILL_EVENT_HISTORY, + DEFAULT_SESSION_FILL_EVENT_HISTORY_ENABLED); + } } diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java index be69d3da3874..d44b941082b5 100644 --- a/core/java/android/window/DesktopModeFlags.java +++ b/core/java/android/window/DesktopModeFlags.java @@ -20,12 +20,13 @@ import android.annotation.Nullable; import android.app.ActivityThread; import android.app.Application; import android.content.ContentResolver; +import android.os.SystemProperties; import android.provider.Settings; import android.util.Log; import com.android.window.flags.Flags; -import java.util.function.Supplier; +import java.util.function.BooleanSupplier; /** * Checks desktop mode flag state. @@ -90,9 +91,35 @@ public enum DesktopModeFlags { INCLUDE_TOP_TRANSPARENT_FULLSCREEN_TASK_IN_DESKTOP_HEURISTIC( Flags::includeTopTransparentFullscreenTaskInDesktopHeuristic, true); - private static final String TAG = "DesktopModeFlagsUtil"; + /** + * Flag class, to be used in case the enum cannot be used because the flag is not accessible. + * + * <p> This class will still use the process-wide cache. + */ + public static class DesktopModeFlag { + // Function called to obtain aconfig flag value. + private final BooleanSupplier mFlagFunction; + // Whether the flag state should be affected by developer option. + private final boolean mShouldOverrideByDevOption; + + public DesktopModeFlag(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption) { + this.mFlagFunction = flagFunction; + this.mShouldOverrideByDevOption = shouldOverrideByDevOption; + } + + /** + * Determines state of flag based on the actual flag and desktop mode developer option + * overrides. + */ + public boolean isTrue() { + return isFlagTrue(mFlagFunction, mShouldOverrideByDevOption); + } + + } + + private static final String TAG = "DesktopModeFlags"; // Function called to obtain aconfig flag value. - private final Supplier<Boolean> mFlagFunction; + private final BooleanSupplier mFlagFunction; // Whether the flag state should be affected by developer option. private final boolean mShouldOverrideByDevOption; @@ -100,7 +127,9 @@ public enum DesktopModeFlags { // be refreshed only on reboots as overridden state is expected to take effect on reboots. private static ToggleOverride sCachedToggleOverride; - DesktopModeFlags(Supplier<Boolean> flagFunction, boolean shouldOverrideByDevOption) { + public static final String SYSTEM_PROPERTY_NAME = "persist.wm.debug.desktop_experience_devopts"; + + DesktopModeFlags(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption) { this.mFlagFunction = flagFunction; this.mShouldOverrideByDevOption = shouldOverrideByDevOption; } @@ -110,24 +139,42 @@ public enum DesktopModeFlags { * overrides. */ public boolean isTrue() { - Application application = ActivityThread.currentApplication(); - if (!Flags.showDesktopWindowingDevOption() - || !mShouldOverrideByDevOption - || application == null) { - return mFlagFunction.get(); - } else { + return isFlagTrue(mFlagFunction, mShouldOverrideByDevOption); + } + + private static boolean isFlagTrue(BooleanSupplier flagFunction, + boolean shouldOverrideByDevOption) { + if (!shouldOverrideByDevOption) return flagFunction.getAsBoolean(); + if (Flags.showDesktopExperienceDevOption()) { + return switch (getToggleOverride(null)) { + case OVERRIDE_UNSET, OVERRIDE_OFF -> flagFunction.getAsBoolean(); + case OVERRIDE_ON -> true; + }; + } + if (Flags.showDesktopWindowingDevOption()) { + Application application = ActivityThread.currentApplication(); + if (application == null) { + Log.w(TAG, "Could not get the current application."); + return flagFunction.getAsBoolean(); + } + ContentResolver contentResolver = application.getContentResolver(); + if (contentResolver == null) { + Log.w(TAG, "Could not get the content resolver for the application."); + return flagFunction.getAsBoolean(); + } boolean shouldToggleBeEnabledByDefault = Flags.enableDesktopWindowingMode(); - return switch (getToggleOverride(application.getContentResolver())) { - case OVERRIDE_UNSET -> mFlagFunction.get(); + return switch (getToggleOverride(contentResolver)) { + case OVERRIDE_UNSET -> flagFunction.getAsBoolean(); // When toggle override matches its default state, don't override flags. This // helps users reset their feature overrides. - case OVERRIDE_OFF -> !shouldToggleBeEnabledByDefault && mFlagFunction.get(); - case OVERRIDE_ON -> shouldToggleBeEnabledByDefault ? mFlagFunction.get() : true; + case OVERRIDE_OFF -> !shouldToggleBeEnabledByDefault && flagFunction.getAsBoolean(); + case OVERRIDE_ON -> !shouldToggleBeEnabledByDefault || flagFunction.getAsBoolean(); }; } + return flagFunction.getAsBoolean(); } - private ToggleOverride getToggleOverride(ContentResolver contentResolver) { + private static ToggleOverride getToggleOverride(@Nullable ContentResolver contentResolver) { // If cached, return it if (sCachedToggleOverride != null) { return sCachedToggleOverride; @@ -143,12 +190,21 @@ public enum DesktopModeFlags { /** * Returns {@link ToggleOverride} from Settings.Global set by toggle. */ - private ToggleOverride getToggleOverrideFromSystem(ContentResolver contentResolver) { - int settingValue = Settings.Global.getInt( - contentResolver, - Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, - ToggleOverride.OVERRIDE_UNSET.getSetting() - ); + private static ToggleOverride getToggleOverrideFromSystem( + @Nullable ContentResolver contentResolver) { + int settingValue; + if (Flags.showDesktopExperienceDevOption()) { + settingValue = SystemProperties.getInt( + SYSTEM_PROPERTY_NAME, + ToggleOverride.OVERRIDE_UNSET.getSetting() + ); + } else { + settingValue = Settings.Global.getInt( + contentResolver, + Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, + ToggleOverride.OVERRIDE_UNSET.getSetting() + ); + } return ToggleOverride.fromSetting(settingValue, ToggleOverride.OVERRIDE_UNSET); } diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index b4e7675402b9..73ebcdd8a07b 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -555,4 +555,11 @@ flag { metadata { purpose: PURPOSE_BUGFIX } -}
\ No newline at end of file +} + +flag { + name: "show_desktop_experience_dev_option" + namespace: "lse_desktop_experience" + description: "Replace the freeform windowing dev options with a desktop experience one." + bug: "389092752" +} diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index c2e305d72dd0..9f6ea42c6fc4 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -180,6 +180,16 @@ flag { } flag { + name: "app_handle_no_relayout_on_exclusion_change" + namespace: "windowing_frontend" + description: "Remove unnecessary relayouts for app handle when exclusion regions change" + bug: "383672263" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "respect_non_top_visible_fixed_orientation" namespace: "windowing_frontend" description: "If top activity is not opaque, respect the fixed orientation of activity behind it" diff --git a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java index e0a77d2be724..1f9df3cc842a 100644 --- a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java @@ -28,6 +28,7 @@ import com.android.internal.protolog.common.IProtoLogGroup; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.util.ArrayList; public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl { @@ -161,15 +162,39 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl { messageString = message.getMessage(mViewerConfigReader); if (messageString == null) { - throw new RuntimeException("Failed to decode message for logcat. " - + "Message hash (" + message.getMessageHash() + ") either not available in " - + "viewerConfig file (" + mViewerConfigFilePath + ") or " - + "not loaded into memory from file before decoding."); + // Either we failed to load the config for this log message from the viewer config file + // into memory, or the message hash is simply not available in the viewer config file. + // We want to confirm that the message hash is not available in the viewer config file + // before throwing an exception. + throw new RuntimeException(getReasonForFailureToGetMessageString(message)); } return messageString; } + private String getReasonForFailureToGetMessageString(Message message) { + if (message.getMessageHash() == null) { + return "Trying to get message from null message hash"; + } + + try { + if (mViewerConfigReader.messageHashIsAvailableInFile(message.getMessageHash())) { + return "Failed to decode message for logcat logging. " + + "Message hash (" + message.getMessageHash() + ") is not available in " + + "viewerConfig file (" + mViewerConfigFilePath + "). This might be due " + + "to the viewer config file and the executing code being out of sync."; + } else { + return "Failed to decode message for logcat. " + + "Message hash (" + message.getMessageHash() + ") was available in the " + + "viewerConfig file (" + mViewerConfigFilePath + ") but wasn't loaded " + + "into memory from file before decoding! This is likely a bug."; + } + } catch (IOException e) { + return "Failed to get string message to log but could not identify the root cause due " + + "to an IO error in reading the viewer config file."; + } + } + private void loadLogcatGroupsViewerConfig(@NonNull IProtoLogGroup[] protoLogGroups) { final var groupsLoggingToLogcat = new ArrayList<String>(); for (IProtoLogGroup protoLogGroup : protoLogGroups) { diff --git a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java index 524f64225084..f77179949fbf 100644 --- a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java +++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java @@ -100,6 +100,36 @@ public class ProtoLogViewerConfigReader { } } + /** + * Return whether or not the viewer config file contains a message with the specified hash. + * @param messageHash The hash message we are looking for in the viewer config file + * @return True iff the message with message hash is contained in the viewer config. + * @throws IOException if there was an issue reading the viewer config file. + */ + public boolean messageHashIsAvailableInFile(long messageHash) + throws IOException { + try (var pisWrapper = mViewerConfigInputStreamProvider.getInputStream()) { + final var pis = pisWrapper.get(); + while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (pis.getFieldNumber() == (int) MESSAGES) { + final long inMessageToken = pis.start(MESSAGES); + + while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (pis.getFieldNumber() == (int) MESSAGE_ID) { + if (pis.readLong(MESSAGE_ID) == messageHash) { + return true; + } + } + } + + pis.end(inMessageToken); + } + } + } + + return false; + } + @NonNull private Map<Long, String> loadViewerConfigMappingForGroup(@NonNull String group) throws IOException { diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 555374a05592..ec3975205542 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -214,6 +214,11 @@ oneway interface IStatusBar void onDisplayReady(int displayId); /** + * Notifies System UI that the system decorations should be removed from the display. + */ + void onDisplayRemoveSystemDecorations(int displayId); + + /** * Notifies System UI side of system bar attribute change on the specified display. * * @param displayId the ID of the display to notify. @@ -395,4 +400,7 @@ oneway interface IStatusBar * @param displayId the id of the current display. */ void moveFocusedTaskToDesktop(int displayId); + + /** Set whether the display should have a navigation bar. */ + void setHasNavigationBar(int displayId, boolean hasNavigationBar); } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 74707703f5f2..3f9650773211 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -1055,7 +1055,7 @@ public class LockPatternUtils { } final int patternSize = pattern.size(); - byte[] res = new byte[patternSize]; + byte[] res = newNonMovableByteArray(patternSize); for (int i = 0; i < patternSize; i++) { LockPatternView.Cell cell = pattern.get(i); res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1'); diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java index 92ce990c67df..2a12c986ab04 100644 --- a/core/java/com/android/internal/widget/LockscreenCredential.java +++ b/core/java/com/android/internal/widget/LockscreenCredential.java @@ -81,9 +81,9 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { /** * Private constructor, use static builder methods instead. * - * <p> Builder methods should create a private copy of the credential bytes and pass in here. - * LockscreenCredential will only store the reference internally without copying. This is to - * minimize the number of extra copies introduced. + * <p> Builder methods should create a private copy of the credential bytes using a non-movable + * array and pass it in here. LockscreenCredential will only store the reference internally + * without copying. This is to minimize the number of extra copies introduced. */ private LockscreenCredential(int type, byte[] credential, boolean hasInvalidChars) { Objects.requireNonNull(credential); @@ -141,7 +141,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { */ public static LockscreenCredential createUnifiedProfilePassword(@NonNull byte[] password) { return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD, - Arrays.copyOf(password, password.length), /* hasInvalidChars= */ false); + copyOfArrayNonMovable(password), /* hasInvalidChars= */ false); } /** @@ -237,7 +237,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { /** Create a copy of the credential */ public LockscreenCredential duplicate() { return new LockscreenCredential(mType, - mCredential != null ? Arrays.copyOf(mCredential, mCredential.length) : null, + mCredential != null ? copyOfArrayNonMovable(mCredential) : null, mHasInvalidChars); } @@ -252,6 +252,15 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { } /** + * Copies the given array into a new non-movable array. + */ + private static byte[] copyOfArrayNonMovable(byte[] array) { + byte[] copy = LockPatternUtils.newNonMovableByteArray(array.length); + System.arraycopy(array, 0, copy, 0, array.length); + return copy; + } + + /** * Checks whether the credential meets basic requirements for setting it as a new credential. * * This is redundant if {@link android.app.admin.PasswordMetrics#validateCredential()}, which @@ -440,7 +449,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { * @return A byte array representing the input */ private static byte[] charsToBytesTruncating(CharSequence chars) { - byte[] bytes = new byte[chars.length()]; + byte[] bytes = LockPatternUtils.newNonMovableByteArray(chars.length()); for (int i = 0; i < chars.length(); i++) { bytes[i] = (byte) chars.charAt(i); } diff --git a/core/res/res/color-night/resolver_profile_tab_text.xml b/core/res/res/color-night/resolver_profile_tab_text.xml deleted file mode 100644 index 61a5140582d0..000000000000 --- a/core/res/res/color-night/resolver_profile_tab_text.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?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. ---> -<selector xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/textColorPrimaryInverse" android:state_selected="true"/> - <item android:color="?androidprv:attr/textColorSecondary"/> -</selector> diff --git a/core/res/res/color-night/surface_effect_0_color.xml b/core/res/res/color-night/surface_effect_0_color.xml new file mode 100644 index 000000000000..f71ed46cc014 --- /dev/null +++ b/core/res/res/color-night/surface_effect_0_color.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2025 The Android Open 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_accent1_800" + android:alpha="0.5"/> +</selector> diff --git a/core/res/res/color-night/surface_effect_1_color.xml b/core/res/res/color-night/surface_effect_1_color.xml new file mode 100644 index 000000000000..80b95ae31d1c --- /dev/null +++ b/core/res/res/color-night/surface_effect_1_color.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2025 The Android Open 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral1_500" + android:lStar="6" android:alpha="0.54"/> +</selector> diff --git a/core/res/res/color/resolver_profile_tab_text.xml b/core/res/res/color/resolver_profile_tab_text.xml index 6b8c42d70cdf..13bdd14e0280 100644 --- a/core/res/res/color/resolver_profile_tab_text.xml +++ b/core/res/res/color/resolver_profile_tab_text.xml @@ -13,8 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> -<selector xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/textColorPrimary" android:state_selected="true"/> - <item android:color="?androidprv:attr/textColorSecondary"/> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@color/materialColorOnPrimary" android:state_selected="true"/> + <item android:color="@color/materialColorOnSurface"/> </selector> diff --git a/core/res/res/color/surface_effect_0_color.xml b/core/res/res/color/surface_effect_0_color.xml new file mode 100644 index 000000000000..b6a607c6ee5e --- /dev/null +++ b/core/res/res/color/surface_effect_0_color.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2025 The Android Open 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_accent1_100" + android:alpha="0.5"/> +</selector> diff --git a/core/res/res/color/surface_effect_1_color.xml b/core/res/res/color/surface_effect_1_color.xml new file mode 100644 index 000000000000..332130ae6f91 --- /dev/null +++ b/core/res/res/color/surface_effect_1_color.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2025 The Android Open 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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral1_500" + android:lStar="98" android:alpha="0.54"/> +</selector> diff --git a/core/res/res/drawable/chooser_row_layer_list.xml b/core/res/res/drawable/chooser_row_layer_list.xml index f5ba1e9d633b..3361fccb70a0 100644 --- a/core/res/res/drawable/chooser_row_layer_list.xml +++ b/core/res/res/drawable/chooser_row_layer_list.xml @@ -19,7 +19,7 @@ <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:shape="rectangle"> - <solid android:color="?android:attr/colorAccentSecondary"/> + <solid android:color="@color/materialColorSecondary"/> <size android:width="128dp" android:height="2dp"/> <corners android:radius="2dp" /> </shape> diff --git a/core/res/res/drawable/inset_resolver_profile_tab_bg.xml b/core/res/res/drawable/inset_resolver_profile_tab_bg.xml new file mode 100644 index 000000000000..8c7b2c09e0f6 --- /dev/null +++ b/core/res/res/drawable/inset_resolver_profile_tab_bg.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright 2025 The Android Open 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 + ~ + ~ https://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. + --> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/resolver_profile_tab_bg" + android:insetLeft="0dp" + android:insetRight="0dp" + android:insetTop="6dp" + android:insetBottom="6dp" /> diff --git a/core/res/res/drawable/resolver_profile_tab_bg.xml b/core/res/res/drawable/resolver_profile_tab_bg.xml index bc9634580007..e36ccc692c6b 100644 --- a/core/res/res/drawable/resolver_profile_tab_bg.xml +++ b/core/res/res/drawable/resolver_profile_tab_bg.xml @@ -29,14 +29,14 @@ <item android:state_selected="false"> <shape android:shape="rectangle"> <corners android:radius="12dp" /> - <solid android:color="?androidprv:attr/colorSurface" /> + <solid android:color="@color/materialColorSurfaceBright" /> </shape> </item> <item android:state_selected="true"> <shape android:shape="rectangle"> <corners android:radius="12dp" /> - <solid android:color="@color/resolver_profile_tab_selected_bg" /> + <solid android:color="@android:color/materialColorPrimary" /> </shape> </item> </selector> diff --git a/core/res/res/layout/resolver_profile_tab_button.xml b/core/res/res/layout/resolver_profile_tab_button.xml index fd168e6414f1..7404dc33be7f 100644 --- a/core/res/res/layout/resolver_profile_tab_button.xml +++ b/core/res/res/layout/resolver_profile_tab_button.xml @@ -18,11 +18,10 @@ <Button xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="0dp" - android:layout_height="36dp" + android:layout_height="48dp" android:layout_weight="1" - android:layout_marginVertical="6dp" android:layout_marginHorizontal="@dimen/resolver_profile_tab_margin" - android:background="@drawable/resolver_profile_tab_bg" + android:background="@drawable/inset_resolver_profile_tab_bg" android:textColor="@color/resolver_profile_tab_text" android:textSize="@dimen/resolver_tab_text_size" android:textAppearance="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 59414771c36c..1c7ce89dc0ad 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Appinhoud is weens sekuriteit van skermdeling verberg"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Outomaties aan satelliet gekoppel"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Jy kan boodskappe stuur en ontvang sonder ’n selfoon- of wi-fi-netwerk"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Jy kan boodskappe stuur en ontvang en beperkte data via satelliet gebruik"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Gebruik satellietboodskappe?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Stuur en ontvang boodskappe sonder ’n selfoon- of wi-fi-netwerk"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Maak Boodskappe oop"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 0ca5ab4a338d..0f5fee4cf9da 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ለደኅንነት ሲባል የመተግበሪያ ይዘት ከማያ ገጽ ማጋራት ተደብቋል"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"ከሳተላይት ጋር በራስ-ሰር ተገናኝቷል"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"ያለ ሞባይል ወይም የWi-Fi አውታረ መረብ መልዕክቶችን መላክ እና መቀበል ይችላሉ"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"በሳተላይት መልዕክቶችን መላክ እና መቀበል እና የተገደበ ውሂብ መጠቀም ይችላሉ"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"የሳተላይት መልዕክት መላላክን ይጠቀማሉ?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"ያለ ሞባይል ወይም የWi-Fi አውታረ መረብ መልዕክቶችን ይላኩ እና ይቀበሉ"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"መልዕክቶች ይክፈቱ"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index cb765e71b801..1fdbe8c35f3e 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -2463,8 +2463,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"تم إخفاء محتوى التطبيق بعد تفعيل ميزة \"مشاركة الشاشة\" للحفاظ على أمانك"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"تم الاتصال تلقائيًا بالقمر الصناعي"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"يمكنك إرسال الرسائل واستلامها بدون شبكة الجوّال أو شبكة Wi-Fi."</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"يمكنك إرسال الرسائل وتلقّيها واستخدام بيانات محدودة عبر القمر الصناعي"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"هل تريد المراسلة عبر القمر الصناعي؟"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"يمكنك إرسال الرسائل واستلامها بدون شبكة الجوّال أو شبكة Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"فتح تطبيق \"الرسائل\""</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 0a4597ec589e..9084407b1c6d 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Tətbiq kontenti güvənlik məsələlərinə görə ekran paylaşımından gizlədildi"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Peykə avtomatik qoşulub"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Mobil və ya Wi-Fi şəbəkəsi olmadan mesaj göndərə və qəbul edə bilərsiniz"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Peyk vasitəsilə mesaj göndərə və qəbul edə, eləcə də məhdud datadan istifadə edə bilərsiniz"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Peyk mesajlaşmasından istifadə edilsin?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Mobil və ya Wi-Fi şəbəkəsi olmadan mesajlar göndərin və qəbul edin"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Mesajı açın"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 5fb744ee2fa9..2abb7f4da9af 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je skriven za deljenje sadržaja ekrana zbog bezbednosti"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automatski povezano sa satelitom"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Možete da šaljete i primate poruke bez mobilne ili WiFi mreže"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Možete da šaljete i primate poruke, kao i da koristite ograničenu količinu podataka preko satelita"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Želite da koristite satelitsku razmenu poruka?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Šaljite i primajte poruke bez mobilne ili WiFi mreže"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvori Messages"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 74c0b46a8045..7f57c8747e23 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -2461,8 +2461,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Змесціва праграмы выключана з абагульвання экрана ў мэтах бяспекі"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Аўтаматычна падключана да сістэм спадарожнікавай сувязі"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Вы можаце адпраўляць і атрымліваць паведамленні без доступу да мабільнай сеткі або Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"З дапамогай спадарожнікавай сувязі вы можаце адпраўляць і атрымліваць паведамленні, а таксама выкарыстоўваць абмежаваную колькасць мабільных даных"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Выкарыстоўваць абмен паведамленнямі па спадарожнікавай сувязі?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Вы можаце адпраўляць і атрымліваць паведамленні, калі падключэнне да мабільнай сеткі або сеткі Wi-Fi адсутнічае"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Адкрыць Паведамленні"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index b857fb52b418..6bff361516e5 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Съдържанието на приложението е скрито от функцията за споделяне на екрана от съображения за сигурност"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Автоматично установена връзка със сателит"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Можете да изпращате и получавате съобщения без мобилна или Wi-Fi мрежа"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Можете да изпращате и получавате съобщения и да използвате ограничени данни чрез сателит"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Да се използват ли сателитни съобщения?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Изпращайте и получавайте съобщения без мобилна или Wi-Fi мрежа"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Отваряне на Messages"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 8da67849c84d..82d1da312905 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"নিরাপত্তার জন্য স্ক্রিন শেয়ার করা থেকে লুকানো অ্যাপের কন্টেন্ট"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"স্যাটেলাইটের সাথে অটোমেটিক কানেক্ট করা হয়েছে"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"আপনি কোনও মেবাইল বা ওয়াই-ফাই নেটওয়ার্ক ছাড়াই মেসেজ পাঠাতে ও পেতে পারবেন"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"আপনি স্যাটেলাইটের মাধ্যমে মেসেজ পাঠাতে ও পেতে এবং সীমিত ডেটা ব্যবহার করতে পারেন"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"\'স্যাটেলাইট মেসেজিং\' ব্যবহার করবেন?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"কোনও মেবাইল বা ওয়াই-ফাই নেটওয়ার্ক ছাড়াই মেসেজ পাঠান ও রিসিভ করুন"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages খুলুন"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 639972915f76..d055f762858b 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je sakriven od dijeljenja ekrana radi sigurnosti"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automatski je povezano sa satelitom"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Možete slati i primati poruke bez mobilne ili WiFi mreže"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Možete slati i primati poruke te koristiti ograničeni prenos podataka putem satelita"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Koristiti satelitsku razmjenu poruka?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Šaljite i primajte poruke bez mobilne ili WiFi mreže"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvorite Messages"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 49d80c25cbfc..2b0e6fca8caa 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contingut de l\'aplicació amagat de la compartició de pantalla per seguretat"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"S\'ha connectat automàticament a un satèl·lit"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Pots enviar i rebre missatges sense una xarxa mòbil o Wi‑Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Pots enviar i rebre missatges i utilitzar dades limitades per satèl·lit"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Vols utilitzar els missatges per satèl·lit?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envia i rep missatges sense una xarxa mòbil o Wi‑Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Obre Missatges"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 8b45d72f9131..e8f75f3b957f 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -304,8 +304,7 @@ <string name="notification_channel_network_alerts" msgid="6312366315654526528">"Síťová upozornění"</string> <string name="notification_channel_network_available" msgid="6083697929214165169">"K dispozici je síť"</string> <string name="notification_channel_vpn" msgid="1628529026203808999">"Stav sítě VPN"</string> - <!-- no translation found for notification_channel_system_time (1660313368058030441) --> - <skip /> + <string name="notification_channel_system_time" msgid="1660313368058030441">"Čas a časová pásma"</string> <string name="notification_channel_device_admin" msgid="6384932669406095506">"Upozornění od vašeho administrátora IT"</string> <string name="notification_channel_alerts" msgid="5070241039583668427">"Upozornění"</string> <string name="notification_channel_retail_mode" msgid="3732239154256431213">"Prodejní ukázka"</string> @@ -313,8 +312,7 @@ <string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplikace je spuštěna"</string> <string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikace spotřebovávají baterii"</string> <string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Zvětšení"</string> - <!-- no translation found for notification_channel_accessibility_hearing_device (7816963856388758952) --> - <skip /> + <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Naslouchátko"</string> <string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Využití přístupnosti"</string> <string name="notification_channel_display" msgid="6905032605735615090">"Displej"</string> <string name="foreground_service_app_in_background" msgid="1439289699671273555">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> využívá baterii"</string> @@ -1412,10 +1410,8 @@ <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Stáhnout aplikaci"</string> <string name="carrier_app_notification_title" msgid="5815477368072060250">"Byla vložena nová SIM karta"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Klepnutím zahájíte nastavení"</string> - <!-- no translation found for time_zone_change_notification_title (5232503069219193218) --> - <skip /> - <!-- no translation found for time_zone_change_notification_body (6135793674904665585) --> - <skip /> + <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Vaše časové pásmo se změnilo"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Jste v časovém pásmu <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Nastavit čas"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Nastavení data"</string> <string name="date_time_set" msgid="4603445265164486816">"Nastavit"</string> @@ -1803,18 +1799,12 @@ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Funkce se otevře při příštím použití této zkratky. Přejeďte dvěma prsty nahoru ze spodní části obrazovky a rychle je zvedněte."</string> <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Funkce se otevře při příštím použití této zkratky. Přejeďte třemi prsty nahoru ze spodní části obrazovky a rychle je zvedněte."</string> <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Zvětšení"</string> - <!-- no translation found for hearing_device_switch_phone_mic_notification_title (6645178038359708836) --> - <skip /> - <!-- no translation found for hearing_device_switch_hearing_mic_notification_title (4612074852145289569) --> - <skip /> - <!-- no translation found for hearing_device_switch_phone_mic_notification_text (1332426273666077412) --> - <skip /> - <!-- no translation found for hearing_device_switch_hearing_mic_notification_text (8288368365767284208) --> - <skip /> - <!-- no translation found for hearing_device_notification_switch_button (3619524619430941300) --> - <skip /> - <!-- no translation found for hearing_device_notification_settings_button (6673651052880279178) --> - <skip /> + <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Přepnout na mikrofon telefonu?"</string> + <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Přepnout na mikrofon naslouchátka?"</string> + <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Pro lepší zvuk, nebo pokud je baterie naslouchátka téměř vybitá. Mikrofon se přepne jen během hovoru."</string> + <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"K handsfree telefonování můžete použít mikrofon naslouchátka. Mikrofon se přepne jen během hovoru."</string> + <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Přepnout"</string> + <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Nastavení"</string> <string name="user_switched" msgid="7249833311585228097">"Aktuální uživatel je <xliff:g id="NAME">%1$s</xliff:g>."</string> <string name="user_switching_message" msgid="1912993630661332336">"Přepínání na uživatele <xliff:g id="NAME">%1$s</xliff:g>…"</string> <string name="user_logging_out_message" msgid="7216437629179710359">"Odhlašování uživatele <xliff:g id="NAME">%1$s</xliff:g>…"</string> @@ -2471,8 +2461,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikace je z bezpečnostních důvodů při sdílení obrazovky skryt"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automaticky připojeno k satelitu"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Zprávy můžete odesílat a přijímat bez mobilní sítě nebo sítě Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Můžete dostávat a odesílat zprávy a používat omezená data přes satelit"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Použít satelitní zprávy?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Odesílejte a přijímejte zprávy bez mobilní sítě nebo Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otevřít Zprávy"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index edd910c9fe6d..288053ee1632 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Af sikkerhedsmæssige årsager vises appindhold ikke ved skærmdeling"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Der blev automatisk oprettet forbindelse til satellit"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Du kan sende og modtage beskeder uden et mobil- eller Wi-Fi-netværk"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Du kan sende og modtage beskeder samt bruge en begrænset mængde data via satellit"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Vil du bruge satellitbeskeder?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Send og modtag beskeder uden et mobil- eller Wi-Fi-netværk"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Åbn Beskeder"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 5262da98d277..10659eb7e42e 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Aus Sicherheitsgründen werden bei der Bildschirmfreigabe App-Inhalte ausgeblendet"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automatisch mit Satellit verbunden"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Du kannst Nachrichten ohne Mobilfunknetz oder WLAN senden und empfangen"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Du kannst Nachrichten senden und empfangen und begrenzte Datenmengen per Satellit nutzen"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Nachrichten per Satellit verwenden?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Du kannst ohne Mobilgerät oder WLAN Nachrichten senden und empfangen"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages öffnen"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 1d194f4e3b22..77a13ed65700 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Για λόγους ασφάλειας, έγινε απόκρυψη του περιεχομένου της εφαρμογής από την κοινή χρήση οθόνης"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Συνδέθηκε αυτόματα με δορυφόρο"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Μπορείτε να στέλνετε και να λαμβάνετε μηνύματα χωρίς δίκτυο κινητής τηλεφωνίας ή Wi-Fi."</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Μπορείτε να στέλνετε και να λαμβάνετε μηνύματα και να χρησιμοποιείτε περιορισμένα δεδομένα μέσω δορυφόρου"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Χρήση της ανταλλαγής μηνυμάτων μέσω δορυφόρου;"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Αποστολή και λήψη μηνυμάτων χωρίς δίκτυο κινητής τηλεφωνίας ή Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Άνοιγμα Messages"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 75432f8b59a6..667f978701f9 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Auto-connected to satellite"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"You can send and receive messages without a mobile or Wi-Fi network"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"You can send and receive messages and use limited data by satellite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Use satellite messaging?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Send and receive messages without a mobile or Wi-Fi network"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 7d642b71028d..4dcece1eb448 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Auto-connected to satellite"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"You can send and receive messages without a mobile or Wi-Fi network"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"You can send and receive messages and use limited data by satellite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Use satellite messaging?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Send and receive messages without a mobile or Wi-Fi network"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index dd8e69550fff..a1f6f7615aba 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Auto-connected to satellite"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"You can send and receive messages without a mobile or Wi-Fi network"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"You can send and receive messages and use limited data by satellite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Use satellite messaging?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Send and receive messages without a mobile or Wi-Fi network"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 3451d58fe747..f34aa97b424a 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Se ocultó el contenido de la app durante el uso compartido de la pantalla por motivos de seguridad"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Conexión automática a satélite"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Puedes enviar y recibir mensajes incluso si no tienes conexión a una red móvil o Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Puedes enviar y recibir mensajes, y usar datos limitados por satélite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"¿Quieres usar la mensajería satelital?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envía y recibe mensajes sin una red móvil ni Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir Mensajes"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 7b9dd4675800..612d86f14ef8 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenido de la aplicación oculto en pantalla compartida por seguridad"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Conectado automáticamente al satélite"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Puedes enviar y recibir mensajes sin una red móvil o Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Puedes enviar y recibir mensajes y usar datos limitados por satélite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"¿Usar mensajes por satélite?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envía y recibe mensajes sin una red móvil ni Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abre Mensajes"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index cf875408ed14..6d5448908b02 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Rakenduse sisu on ekraani jagamisel turvalisuse huvides peidetud"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Satelliidiga loodi automaatselt ühendus"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Teil on võimalik sõnumeid saata ja vastu võtta ilma mobiilside- ja WiFi-võrguta"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Saate sõnumeid vahetada ja kasutada piiratud andmeid satelliidi kaudu"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Kas soovite kasutada satelliidipõhist sõnumsidet?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Sõnumite saatmine ja vastuvõtmine ilma mobiilside- või WiFi-võrguta"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ava rakendus Messages"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 8e689594ea2a..9f62847bb710 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Aplikazioko edukia ezkutatu egin da pantaila partekatzeko eginbidetik, segurtasuna bermatzeko"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automatikoki konektatu da satelitera"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Mezuak bidal eta jaso ditzakezu sare mugikorrik edo wifi-sarerik gabe"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Satelite bidez mezuak bidali eta jasotzeko nahiz datuak muga batekin erabiltzeko aukera duzu"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Satelite bidezko mezularitza erabili nahi duzu?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Bidali eta jaso mezuak sare mugikorrik edo wifi-sarerik gabe"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ireki Mezuak"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 9f2c7bb43c69..e8e0f48a966e 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -169,7 +169,7 @@ <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"درحالحاضر تماسها، پیامها، و دادهها هنگام استفاده از سیمکارت <xliff:g id="NETWORK_NAME">%1$s</xliff:g> آسیبپذیرتر هستند.\n\nوقتی اتصال شما دوباره رمزگذاری شود، اعلان دیگری دریافت خواهید کرد."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"تنظیمات امنیت شبکه تلفن همراه"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"بیشتر بدانید"</string> - <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"متوجهام"</string> + <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"متوجهم"</string> <string name="fcComplete" msgid="1080909484660507044">"کد ویژگی کامل شد."</string> <string name="fcError" msgid="5325116502080221346">"مشکل در اتصال یا کد ویژگی نامعتبر."</string> <string name="httpErrorOk" msgid="6206751415788256357">"تأیید"</string> @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"بهدلایل امنیتی، محتوای برنامه پساز همرسانی صفحهنمایش پنهان میشود"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"بهطور خودکار به ماهواره متصل شد"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"میتوانید بدون شبکه تلفن همراه یا Wi-Fi پیام ارسال و دریافت کنید"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"ازطریق ماهواره میتوانید پیام ارسال و دریافت کنید و از دادههای محدود استفاده کنید"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"از «پیامرسانی ماهوارهای» استفاده شود؟"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"ارسال و دریافت پیام بدون شبکه تلفن همراه یا Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"باز کردن «پیامنگار»"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 0b65ee2c5403..5da5844cd9c3 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sovelluksen sisältö piilotettu näytön jakamiselta turvallisuussyistä"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Yhdistetty automaattisesti satelliittiin"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Voit lähettää ja vastaanottaa viestejä ilman mobiili‑ tai Wi-Fi-verkkoa"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Voit lähettää ja vastaanottaa viestejä ja käyttää rajoitetusti dataa satelliitin kautta"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Käytetäänkö satelliittiviestintää?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Lähetä ja vastaanota viestejä ilman mobiili- tai Wi-Fi-verkkoa"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Avaa Messages"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index e9331bb826c4..9d81f4f978bd 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'appli est masqué du Partage d\'écran par mesure de sécurité"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Connecté au satellite automatiquement"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Vous pouvez envoyer et recevoir des messages sans avoir recours à un appareil mobile ou à un réseau Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Vous pouvez envoyer et recevoir des messages, et utiliser des données limitées par satellite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Utiliser la messagerie par satellite?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envoyez et recevez des messages sans réseau cellulaire ou Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ouvrir Messages"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index cbcc961f309a..9ef2758b4eee 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'appli est masqué lors du partage d\'écran par mesure de sécurité"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Connecté automatiquement au réseau satellite"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Vous pouvez envoyer et recevoir des messages sans connexion au réseau mobile ou Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Vous pouvez envoyer ou recevoir des messages et utiliser une certaine quantité de données par satellite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Utiliser la messagerie par satellite ?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envoyer et recevoir des messages sans réseau mobile ou Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ouvrir Messages"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 25aac2cd0615..d775f448d2ce 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Por seguranza, ocultouse o contido da aplicación na pantalla compartida"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Conexión automática ao satélite"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Podes enviar e recibir mensaxes sen unha rede de telefonía móbil ou wifi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Podes enviar e recibir mensaxes, ademais de usar datos limitados por satélite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Queres usar a mensaxaría por satélite?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Envía e recibe mensaxes sen ter acceso a redes de telefonía móbil ou wifi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir Mensaxes"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index c38768dc3e30..f4d6099fffe8 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"સુરક્ષા માટે સ્ક્રીન શેર કરતી વખતે ઍપનું કન્ટેન્ટ છુપાવેલું છે"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"સેટેલાઇટ સાથે ઑટોમૅટિક રીતે કનેક્ટેડ"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"તમે મોબાઇલ અથવા વાઇ-ફાઇ નેટવર્ક વિના મેસેજ મોકલી અને પ્રાપ્ત કરી શકો છો"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"તમે મેસેજ મોકલી અને પ્રાપ્ત કરી શકો છો અને સૅટલાઇટ દ્વારા મર્યાદિત ડેટાનો ઉપયોગ કરી શકો છો"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"શું સૅટલાઇટ મેસેજિંગનો ઉપયોગ કરીએ?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"મોબાઇલ કે વાઇ-ફાઇ નેટવર્ક વિના મેસેજ મોકલો અને મેળવો"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ખોલો"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 6199c806d5e2..d750b39a0e41 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -291,7 +291,7 @@ <string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string> <string name="notification_compact_heads_up_reply" msgid="2425293958371284340">"जवाब दें"</string> <string name="notification_hidden_text" msgid="2835519769868187223">"नई सूचना"</string> - <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"सामान्य कीबोर्ड"</string> + <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"फ़िज़िकल कीबोर्ड"</string> <string name="notification_channel_security" msgid="8516754650348238057">"सुरक्षा"</string> <string name="notification_channel_car_mode" msgid="2123919247040988436">"कार मोड"</string> <string name="notification_channel_account" msgid="6436294521740148173">"खाते की स्थिति"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 5b3dc7c86658..b5fc19a3e961 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije sakriven je od dijeljenja zaslona radi sigurnosti"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automatski povezano sa satelitom"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Možete slati i primati poruke bez mobilne mreže ili Wi-Fi mreže"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Možete slati i primati poruke te koristiti ograničene podatke putem satelita"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Želite li slati poruke putem satelita?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Šaljite i primajte poruke kad nije dostupna mobilna ili Wi-Fi mreža"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvori Poruke"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 117509955341..f42567ed1fe6 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Apptartalom elrejtve a megosztástól a biztonság érdekében"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automatikusan csatlakozva a műholdhoz"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Küldhet és fogadhat üzeneteket mobil- és Wi-Fi-hálózat nélkül is"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Küldhet és fogadhat üzeneteket, valamint korlátozott mennyiségű adatot használhat műholdon keresztül"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Műholdas üzenetváltást szeretne használni?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Küldhet és fogadhat üzeneteket mobil- és Wi-Fi-hálózat nélkül is"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"A Messages megnyitása"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index c89544823314..e3fa611ce135 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Անվտանգության նկատառումներով՝ բովանդակությունը թաքցվել է ցուցադրումից"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Ավտոմատ միացել է արբանյակին"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Դուք կարող եք հաղորդագրություններ ուղարկել և ստանալ առանց բջջային կամ Wi-Fi կապի"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Դուք կարող եք արբանյակի միջոցով ուղարկել և ստանալ հաղորդագրություններ և օգտագործել սահմանափակ ծավալի ինտերնետ թրաֆիկ"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Օգտագործե՞լ արբանյակային հաղորդագրումը"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Ուղարկեք և ստացեք հաղորդագրություններ առանց բջջային կամ Wi-Fi ցանցի"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Բացել Messages-ը"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 26a79e0b53a9..5f60ba2de8e4 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Konten aplikasi disembunyikan dari berbagi layar karena alasan keamanan"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Menghubungkan otomatis ke satelit"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Anda dapat mengirim dan menerima pesan tanpa jaringan seluler atau Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Anda dapat mengirim dan menerima pesan serta menggunakan data terbatas melalui satelit"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Gunakan fitur pesan satelit?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Mengirim dan menerima pesan tanpa jaringan seluler atau Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Buka Message"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index f6d043b170ed..92567427b0b9 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Efni forrits falið í skjádeilingu af öryggisástæðum"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Tengdist sjálfkrafa við gervihnött"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Þú getur sent og móttekið skilaboð án tengingar við farsímakerfi eða Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Þú getur sent og móttekið skilaboð og notað takmörkuð gögn gegnum gervihnött"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Nota skilaboð í gegnum gervihnött?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Senda og fá skilaboð án tengingar við farsímakerfi eða Wi-Fi-net"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Opna Messages"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 96075003f0b2..34b179fae4ed 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenuti dell\'app nascosti dalla condivisione schermo per sicurezza"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Connessione automatica al satellite"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Puoi inviare e ricevere messaggi senza una rete mobile o Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Puoi inviare e ricevere messaggi e utilizzare dati limitati via satellite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Utilizzare i messaggi via satellite?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Invia e ricevi messaggi senza una rete mobile o Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Apri Messaggi"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index d25cf01602e4..ffca8688ac51 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -303,8 +303,7 @@ <string name="notification_channel_network_alerts" msgid="6312366315654526528">"התראות רשת"</string> <string name="notification_channel_network_available" msgid="6083697929214165169">"יש רשת זמינה"</string> <string name="notification_channel_vpn" msgid="1628529026203808999">"סטטוס ה-VPN"</string> - <!-- no translation found for notification_channel_system_time (1660313368058030441) --> - <skip /> + <string name="notification_channel_system_time" msgid="1660313368058030441">"זמן ואזורי זמן"</string> <string name="notification_channel_device_admin" msgid="6384932669406095506">"התראות ממנהל ה-IT"</string> <string name="notification_channel_alerts" msgid="5070241039583668427">"התראות"</string> <string name="notification_channel_retail_mode" msgid="3732239154256431213">"הדגמה לקמעונאים"</string> @@ -312,8 +311,7 @@ <string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"אפליקציה פועלת"</string> <string name="notification_channel_foreground_service" msgid="7102189948158885178">"אפליקציות שמרוקנות את הסוללה"</string> <string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"הגדלה"</string> - <!-- no translation found for notification_channel_accessibility_hearing_device (7816963856388758952) --> - <skip /> + <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"מכשיר שמיעה"</string> <string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"שימוש בנגישות"</string> <string name="notification_channel_display" msgid="6905032605735615090">"מסך"</string> <string name="foreground_service_app_in_background" msgid="1439289699671273555">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> משתמשת בסוללה"</string> @@ -1411,10 +1409,8 @@ <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"להורדת האפליקציה"</string> <string name="carrier_app_notification_title" msgid="5815477368072060250">"ה-SIM החדש הוכנס"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"יש ללחוץ כדי להגדיר"</string> - <!-- no translation found for time_zone_change_notification_title (5232503069219193218) --> - <skip /> - <!-- no translation found for time_zone_change_notification_body (6135793674904665585) --> - <skip /> + <string name="time_zone_change_notification_title" msgid="5232503069219193218">"אזור הזמן שלך השתנה"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"אזור הזמן הנוכחי שלך הוא <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"הגדרת שעה"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"הגדרת תאריך"</string> <string name="date_time_set" msgid="4603445265164486816">"הגדרה"</string> @@ -1463,7 +1459,7 @@ <string name="select_input_method" msgid="3971267998568587025">"בחירה של שיטת הזנה"</string> <string name="input_method_language_settings" msgid="8069089418056819437">"הגדרות שפה"</string> <string name="show_ime" msgid="6406112007347443383">"להשאיר במסך בזמן שהמקלדת הפיזית פעילה"</string> - <string name="hardware" msgid="3611039921284836033">"שימוש במקלדת שמופיעה במסך"</string> + <string name="hardware" msgid="3611039921284836033">"שימוש במקלדת הווירטואלית"</string> <string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"הגדרה של <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string> <string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"הגדרת מקלדות פיזיות"</string> <string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"יש ללחוץ כדי לבחור שפה ופריסה"</string> @@ -1802,18 +1798,12 @@ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"התכונה תיפתח בפעם הבאה שייעשה שימוש במקש הקיצור הזה. צריך להחליק למעלה עם 2 אצבעות מהחלק התחתון של המסך ולשחרר במהירות."</string> <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"התכונה תיפתח בפעם הבאה שייעשה שימוש במקש הקיצור הזה. צריך להחליק למעלה עם 3 אצבעות מהחלק התחתון של המסך ולשחרר במהירות."</string> <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"הגדלה"</string> - <!-- no translation found for hearing_device_switch_phone_mic_notification_title (6645178038359708836) --> - <skip /> - <!-- no translation found for hearing_device_switch_hearing_mic_notification_title (4612074852145289569) --> - <skip /> - <!-- no translation found for hearing_device_switch_phone_mic_notification_text (1332426273666077412) --> - <skip /> - <!-- no translation found for hearing_device_switch_hearing_mic_notification_text (8288368365767284208) --> - <skip /> - <!-- no translation found for hearing_device_notification_switch_button (3619524619430941300) --> - <skip /> - <!-- no translation found for hearing_device_notification_settings_button (6673651052880279178) --> - <skip /> + <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"להחליף למיקרופון של הטלפון?"</string> + <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"להחליף למיקרופון של מכשיר השמיעה?"</string> + <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"כדי לשמוע טוב יותר או אם הסוללה של מכשיר השמיעה נחלשת. במצב הזה המיקרופון מוחלף רק במהלך השיחה."</string> + <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"אפשר לשוחח במצב דיבורית באמצעות המיקרופון של מכשיר השמיעה. במצב הזה המיקרופון מוחלף רק במהלך השיחה."</string> + <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"החלפה"</string> + <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"הגדרות"</string> <string name="user_switched" msgid="7249833311585228097">"המשתמש הנוכחי <xliff:g id="NAME">%1$s</xliff:g>."</string> <string name="user_switching_message" msgid="1912993630661332336">"מעבר אל <xliff:g id="NAME">%1$s</xliff:g>…"</string> <string name="user_logging_out_message" msgid="7216437629179710359">"מתבצע ניתוק של <xliff:g id="NAME">%1$s</xliff:g>…"</string> @@ -2470,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"תוכן האפליקציה מוסתר משיתוף המסך מטעמי אבטחה"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"חיבור אוטומטי ללוויין"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"אפשר לשלוח ולקבל הודעות ללא רשת סלולרית או רשת Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"אפשר לשלוח ולקבל הודעות ולהשתמש בחבילת הגלישה באופן מוגבל באמצעות לוויין"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"רוצה לשלוח הודעות באמצעות תקשורת לוויינית?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"אפשר לשלוח ולקבל הודעות ללא רשת סלולרית או Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"לפתיחת Messages"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index e1fd8d1a8d82..3f3881b0d598 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Қауіпсіздік мақсатында қолданба контенті экранды көрсету кезінде жасырылды."</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Жерсерік қызметіне автоматты түрде қосылды"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Мобильдік не Wi-Fi желісіне қосылмастан хабар жібере аласыз және ала аласыз."</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Жерсерік арқылы хабар жіберуге және алуға, деректерді шектеулі көлемде пайдалануға болады."</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Жерсерік арқылы хабар алмасасыз ба?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Хабарландыруларды мобильдік желіге немесе Wi-Fi желісіне қосылмай жіберіңіз және алыңыз."</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages қолданбасын ашу"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 190693976be1..0ad4f09d1cfa 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"បានលាក់ខ្លឹមសារកម្មវិធីពីការបង្ហាញអេក្រង់ដើម្បីសុវត្ថិភាព"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"ភ្ជាប់ដោយស្វ័យប្រវត្តិទៅផ្កាយរណប"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"អ្នកអាចផ្ញើ និងទទួលសារដោយមិនប្រើបណ្តាញទូរសព្ទចល័ត ឬ Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"អ្នកអាចផ្ញើ និងទទួលសារ ព្រមទាំងប្រើទិន្នន័យមានកំណត់តាមរយៈផ្កាយរណប"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"ប្រើការផ្ញើសារតាមផ្កាយរណបឬ?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"ផ្ញើ និងទទួលសារដោយគ្មានបណ្ដាញ Wi-Fi ឬបណ្ដាញទូរសព្ទចល័ត"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"បើកកម្មវិធី Messages"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 9c11160f502d..c65dd276be8d 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ಭದ್ರತೆಗಾಗಿ ಸ್ಕ್ರೀನ್ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯಲ್ಲಿ ಆ್ಯಪ್ ಕಂಟೆಂಟ್ ಅನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"ಸ್ಯಾಟಲೈಟ್ಗೆ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"ನೀವು ಮೊಬೈಲ್ ಅಥವಾ ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ ಇಲ್ಲದೆಯೇ ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಬಹುದು ಮತ್ತು ಸ್ವೀಕರಿಸಬಹುದು"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"ನೀವು ಸ್ಯಾಟಲೈಟ್ ಮೂಲಕ ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಬಹುದು ಮತ್ತು ಸ್ವೀಕರಿಸಬಹುದು ಹಾಗೂ ಸೀಮಿತ ಡೇಟಾವನ್ನು ಬಳಸಬಹುದು"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"ಸ್ಯಾಟಲೈಟ್ ಮೆಸೇಜಿಂಗ್ ಅನ್ನು ಬಳಸಬೇಕೆ?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"ಮೊಬೈಲ್ ಅಥವಾ ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ ಇಲ್ಲದೆಯೇ ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಿ ಮತ್ತು ಸ್ವೀಕರಿಸಿ"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ಅನ್ನು ತೆರೆಯಿರಿ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 1b302e633fa7..a52da3c6b91e 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"보안을 위해 화면 공유에서 앱 콘텐츠가 숨겨집니다."</string> <string name="satellite_notification_title" msgid="4026338973463121526">"위성에 자동 연결됨"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"모바일 또는 Wi-Fi 네트워크 없이 메시지를 주고 받을 수 있습니다"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"위성으로 메시지를 주고받을 수 있으며 데이터를 제한적으로 사용할 수도 있습니다."</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"위성 메시지를 사용하시겠습니까?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"모바일 또는 Wi-Fi 네트워크 없이 메시지 주고받기"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"메시지 열기"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 58a6d8486caf..ff743fc42bd3 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Коопсуздук үчүн колдонмодогу контент бөлүшүлгөн экрандан жашырылды"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Спутникке автоматтык түрдө туташтырылган"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Сиз мобилдик же Wi-Fi тармагы жок эле билдирүүлөрдү жөнөтүп, ала аласыз"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Спутник аркылуу билдирүүлөрдү жөнөтүп жана алып, чектелген трафикти колдоно аласыз"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Спутник аркылуу байланышасызбы?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Мобилдик же Wi-Fi тармагына туташпай эле билдирүүлөрдү жөнөтүп, алыңыз"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Жазышуулар колдонмосун ачуу"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 3c3c58ba281a..6f32d875c2c8 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ເນື້ອຫາແອັບຖືກເຊື່ອງໄວ້ຈາກການແບ່ງປັນໜ້າຈໍເພື່ອຄວາມປອດໄພ"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"ເຊື່ອມຕໍ່ກັບດາວທຽມໂດຍອັດຕະໂນມັດ"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"ທ່ານສາມາດສົ່ງ ແລະ ຮັບຂໍ້ຄວາມໂດຍບໍ່ຕ້ອງໃຊ້ເຄືອຂ່າຍມືຖື ຫຼື Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"ທ່ານສາມາດສົ່ງ ແລະ ຮັບຂໍ້ຄວາມ ແລະ ໃຊ້ຂໍ້ມູນທີ່ບໍ່ຈໍາກັດຜ່ານດາວທຽມ"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"ໃຊ້ການຮັບສົ່ງຂໍ້ຄວາມຜ່ານດາວທຽມບໍ?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"ຮັບ ແລະ ສົ່ງຂໍ້ຄວາມໂດຍບໍ່ຕ້ອງໃຊ້ເຄືອຂ່າຍໂທລະສັບມືຖື ຫຼື Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"ເປີດ Messages"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 3c56808d883e..1035fed764f4 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -2461,8 +2461,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Programos turinys paslėptas bendrinant ekraną saugumo sumetimais"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automatiškai prisijungta prie palydovinio ryšio"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Galite siųsti ir gauti pranešimus be mobiliojo ryšio ar „Wi-Fi“ tinklo"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Galite siųsti ir gauti pranešimus bei naudoti ribotus duomenis per palydovą"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Naudoti susirašinėjimą palydoviniais pranešimais?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Siųskite ir gaukite pranešimus be mobiliojo ryšio ar „Wi-Fi“ tinklo"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Atidaryti programą „Messages“"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 1870883fcc5e..a643b9861312 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Drošības nolūkos lietotnes saturs kopīgotajā ekrānā ir paslēpts"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automātiski izveidots savienojums ar satelītu"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Varat sūtīt un saņemt ziņojumus bez mobilā vai Wi-Fi tīkla."</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Varat sūtīt un saņemt ziņojumus un izmantot ierobežotu datu apjomu, lietojot satelītu."</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Vai izmantot satelīta ziņojumapmaiņu?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Sūtiet un saņemiet ziņojumus bez mobilā vai Wi‑Fi tīkla."</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Atvērt lietotni Ziņojumi"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 1c9e022ca3aa..774e4edc1cd6 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Од безбедносни причини, содржините на апликацијата се скриени од споделувањето екран"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Поврзано со сателит автоматски"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Може да испраќате и примате пораки без мобилна или Wi-Fi мрежа"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Може да испраќате и да примате пораки и да користите ограничен интернет преку сателит"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Да се користи „Сателитска размена на пораки“?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Испраќајте и примајте пораки без мобилна или Wi-Fi мрежа"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Отворете ја Messages"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index e70a95ce77d2..9dbfc1e58e89 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Аюулгүй байдлын үүднээс аппын контентыг дэлгэц хуваалцахаас нуусан"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Хиймэл дагуулд автоматаар холбогдсон"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Та мобайл эсвэл Wi-Fi сүлжээгүйгээр мессеж илгээх болон хүлээн авах боломжтой"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Та хиймэл дагуулаар мессеж илгээх, хүлээн авах, хязгаарлагдмал дата ашиглах боломжтой"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Хиймэл дагуулаар дамжин мессеж бичихийг ашиглах уу?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Хөдөлгөөнт холбооны эсвэл Wi-Fi сүлжээгүйгээр мессеж илгээх болон хүлээн авах"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Мессежийг нээх"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index cbe6b979d1d8..750988a242b7 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रीन शेअर करताना सुरक्षेसाठी अॅपमधील आशय लपवला आहे"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"उपग्रहाशी आपोआप कनेक्ट केलेले आहे"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"तुम्ही मोबाइल किंवा वाय-फाय नेटवर्कशिवाय मेसेज पाठवू आणि मिळवू शकता"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"तुम्ही उपग्रहाद्वारे मेसेज पाठवू आणि मिळवू शकता व मर्यादित डेटा वापरू शकता"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"सॅटेलाइट मेसेजिंग वापरायचे आहे का?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"मोबाइल किंवा वाय-फाय नेटवर्कशिवाय मेसेज पाठवणे आणि मिळवणे"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages उघडा"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 432f7f9c6aa0..76086336514f 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"လုံခြုံရေးအတွက် အက်ပ်အကြောင်းအရာကို ဖန်သားပြင် မျှဝေခြင်းတွင် ဖျောက်ထားသည်"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"ဂြိုဟ်တုနှင့် အလိုအလျောက် ချိတ်ဆက်ထားသည်"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"မိုဘိုင်း (သို့) Wi-Fi ကွန်ရက်မရှိဘဲ မက်ဆေ့ဂျ်များကို ပို့နိုင်၊ လက်ခံနိုင်သည်"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"ဂြိုဟ်တုဖြင့် မက်ဆေ့ဂျ်များ ပေးပို့လက်ခံနိုင်ပြီး အကန့်အသတ်ဖြင့် ဒေတာသုံးနိုင်သည်"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"ဂြိုဟ်တုမှတစ်ဆင့် မက်ဆေ့ဂျ်ပို့ခြင်း သုံးမလား။"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"မိုဘိုင်း (သို့) Wi-Fi ကွန်ရက်မရှိဘဲ မက်ဆေ့ဂျ်များ ပို့နိုင်၊ လက်ခံနိုင်သည်"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ဖွင့်ရန်"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index c80a9605fcde..6bd4598709e6 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av sikkerhetsgrunner er appinnholdet skjult for skjermdelingen"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automatisk tilkoblet satellitt"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Du kan sende og motta meldinger uten mobil- eller wifi-nettverk"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Du kan sende og motta meldinger og bruke begrensede data via satellitt"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Vil du bruke satellittmeldinger?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Send og motta meldinger uten mobil- eller wifi-nettverk"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Åpne Meldinger"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index bf7bbaf872be..b94c2f618d6b 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रिन सेयर गर्दा सुरक्षाका लागि एपमा भएको सामग्री लुकाइएको छ"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"स्याटलाइटमा स्वतः कनेक्ट गरियो"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"तपाईं मोबाइल वा Wi-Fi नेटवर्कविनै म्यासेज पठाउन र प्राप्त गर्न सक्नुहुन्छ"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"तपाईं स्याटलाइटमार्फत म्यासेजहरू पठाउन तथा प्राप्त गर्न र सीमित डेटा प्रयोग गर्न सक्नुहुन्छ"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"स्याटलाइटमार्फत म्यासेज पठाउने सुविधा प्रयोग गर्ने हो?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"मोबाइल वा Wi-Fi नेटवर्कविनै म्यासेजहरू पठाउनुहोस् र प्राप्त गर्नुहोस्"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages खोल्नुहोस्"</string> diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml index d3f998fb70cf..7b9b2d666292 100644 --- a/core/res/res/values-night/colors.xml +++ b/core/res/res/values-night/colors.xml @@ -47,6 +47,10 @@ <color name="language_picker_item_selected_bg">#92B3F2</color> <color name="language_picker_item_selected_stroke">#185ABC</color> + <!-- Color for various surfaces related to system-wide blur --> + <color name="surface_effect_0">@color/surface_effect_0_color</color> + <color name="surface_effect_1">@color/surface_effect_1_color</color> + <!-- Color for side fps toast dark theme--> <color name="side_fps_toast_background">#2E3132</color> <color name="side_fps_text_color">#EFF1F2</color> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 695a706dcdb4..52d9106cebfd 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Vanwege beveiligingsrisico\'s is app-content verborgen voor scherm delen"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automatisch verbonden met satelliet"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Je kunt berichten sturen en krijgen zonder een mobiel of wifi-netwerk"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Je kunt berichten sturen en krijgen en beperkte data via satelliet gebruiken"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Satellietberichten gebruiken?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Stuur en krijg berichten zonder mobiel of wifi-netwerk"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Berichten openen"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index de95a033ec20..ba2560f66ae5 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -1408,7 +1408,7 @@ <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ଆପ୍ ଡାଉନଲୋଡ କରନ୍ତୁ"</string> <string name="carrier_app_notification_title" msgid="5815477368072060250">"ନୂଆ SIM କାର୍ଡ ଭର୍ତ୍ତି କରାଗଲା"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"ଏହା ସେଟଅପ୍ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> - <string name="time_zone_change_notification_title" msgid="5232503069219193218">"ଆପଣଙ୍କର ଟାଇମ ଜୋନ ବଦଳିଛି"</string> + <string name="time_zone_change_notification_title" msgid="5232503069219193218">"ଆପଣଙ୍କ ଟାଇମ ଜୋନ ପରିବର୍ତ୍ତନ ହୋଇଛି"</string> <string name="time_zone_change_notification_body" msgid="6135793674904665585">"ଆପଣ ବର୍ତ୍ତମାନ <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)ରେ ଅଛନ୍ତି"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"ସମୟ ସେଟ୍ କରନ୍ତୁ"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"ତାରିଖ ସେଟ୍ କରନ୍ତୁ"</string> @@ -1799,9 +1799,9 @@ <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"ମେଗ୍ନିଫିକେସନ"</string> <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"ଫୋନ ମାଇକକୁ ସୁଇଚ କରିବେ?"</string> <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"ଶ୍ରବଣ ଯନ୍ତ୍ର ମାଇକକୁ ସୁଇଚ କରିବେ?"</string> - <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"ଭଲ ସାଉଣ୍ଡ ପାଇଁ କିମ୍ବା ଯଦି ଆପଣଙ୍କର ଶ୍ରବଣ ଯନ୍ତ୍ର ବ୍ୟାଟେରୀ କମ ଥିଲେ। କଲ ସମୟରେ ଏହା କେବଳ ଆପଣଙ୍କର ମାଇକ ସୁଇଚ କରିଥାଏ।"</string> - <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ହେଣ୍ଡସ-ଫ୍ରି କଲିଂ ପାଇଁ ଆପଣ ଆପଣଙ୍କର ଶ୍ରବଣ ଯନ୍ତ୍ର ମାଇକ୍ରୋଫୋନ ବ୍ୟବହାର କରିପାରିବେ। କଲ ସମୟରେ ଏହା କେବଳ ଆପଣଙ୍କର ମାଇକ ସୁଇଚ କରିଥାଏ।"</string> - <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ସ୍ୱିଚ କରନ୍ତୁ"</string> + <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"ଭଲ ସାଉଣ୍ଡ ପାଇଁ କିମ୍ବା ଯଦି ଆପଣଙ୍କର ଶ୍ରବଣ ଯନ୍ତ୍ର ବେଟେରୀ କମ ଥିଲେ। କଲ ସମୟରେ ଏହା କେବଳ ଆପଣଙ୍କର ମାଇକକୁ ସୁଇଚ କରିଥାଏ।"</string> + <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ହେଣ୍ଡସ-ଫ୍ରି କଲିଂ ପାଇଁ ଆପଣ ଆପଣଙ୍କର ଶ୍ରବଣ ଯନ୍ତ୍ର ମାଇକ୍ରୋଫୋନ ବ୍ୟବହାର କରିପାରିବେ। କଲ ସମୟରେ ଏହା କେବଳ ଆପଣଙ୍କର ମାଇକକୁ ସୁଇଚ କରିଥାଏ।"</string> + <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ସୁଇଚ କରନ୍ତୁ"</string> <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ସେଟିଂସ"</string> <string name="user_switched" msgid="7249833311585228097">"ବର୍ତ୍ତମାନର ୟୁଜର୍ ହେଉଛନ୍ତି <xliff:g id="NAME">%1$s</xliff:g>।"</string> <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>ରେ ସ୍ୱିଚ କରନ୍ତୁ…"</string> @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ସୁରକ୍ଷା ପାଇଁ ସ୍କ୍ରିନ ସେୟାରରୁ ଆପ ବିଷୟବସ୍ତୁକୁ ଲୁଚାଯାଇଛି"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"ସାଟେଲାଇଟ ସହ ସ୍ୱତଃ କନେକ୍ଟ ହୋଇଛି"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"ଏକ ମୋବାଇଲ କିମ୍ବା ୱାଇ-ଫାଇ ନେଟୱାର୍କ ବିନା ଆପଣ ମେସେଜ ପଠାଇପାରିବେ ଏବଂ ପାଇପାରିବେ"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"ସେଟେଲାଇଟ ମାଧ୍ୟମରେ ଆପଣ ମେସେଜ ପଠାଇପାରିବେ ଓ ପାଇପାରିବେ ଏବଂ ସୀମିତ ଡାଟା ବ୍ୟବହାର କରିପାରିବେ"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"ସେଟେଲାଇଟ ମେସେଜିଂକୁ ବ୍ୟବହାର କରିବେ?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"ଏକ ମୋବାଇଲ କିମ୍ବା ୱାଇ-ଫାଇ ନେଟୱାର୍କ ବିନା ମେସେଜ ପଠାନ୍ତୁ ଏବଂ ପାଆନ୍ତୁ"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ଖୋଲନ୍ତୁ"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 4d4b10bb25db..2d2f9c01a4c3 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ਐਪ ਸਮੱਗਰੀ ਨੂੰ ਸੁਰੱਖਿਆ ਲਈ ਸਕ੍ਰੀਨ ਸਾਂਝਾਕਰਨ ਤੋਂ ਲੁਕਾਇਆ ਗਿਆ ਹੈ"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"ਸੈਟੇਲਾਈਟ ਨਾਲ ਸਵੈ-ਕਨੈਕਟ ਹੋਇਆ"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"ਤੁਸੀਂ ਮੋਬਾਈਲ ਜਾਂ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਤੋਂ ਬਿਨਾਂ ਸੁਨੇਹੇ ਭੇਜ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੇ ਹੋ"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"ਤੁਸੀਂ ਸੁਨੇਹੇ ਭੇਜ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੇ ਹੋ ਅਤੇ ਸੈਟੇਲਾਈਟ ਰਾਹੀਂ ਸੀਮਤ ਡਾਟਾ ਵਰਤ ਸਕਦੇ ਹੋ"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"ਕੀ ਸੈਟੇਲਾਈਟ ਸੁਨੇਹੇ ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"ਮੋਬਾਈਲ ਜਾਂ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਤੋਂ ਬਿਨਾਂ ਸੁਨੇਹੇ ਭੇਜੋ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰੋ"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ਐਪ ਖੋਲ੍ਹੋ"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index cc4b251c7713..91c7adc58eb3 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo oculto no compartilhamento de tela por segurança"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Conectado automaticamente ao satélite"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Você pode enviar e receber mensagens sem um dispositivo móvel ou uma rede Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"É possível enviar e receber mensagens e usar dados limitados via satélite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Usar mensagens via satélite?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Enviar e receber mensagens sem uma rede móvel ou Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir o app Mensagens"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index cc4b251c7713..91c7adc58eb3 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo oculto no compartilhamento de tela por segurança"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Conectado automaticamente ao satélite"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Você pode enviar e receber mensagens sem um dispositivo móvel ou uma rede Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"É possível enviar e receber mensagens e usar dados limitados via satélite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Usar mensagens via satélite?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Enviar e receber mensagens sem uma rede móvel ou Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir o app Mensagens"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 25b0471347c9..0fcd12bfbc01 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conținutul aplicației este ascuns de permiterea accesului la ecran din motive de securitate"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"S-a conectat automat la satelit"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Poți să trimiți și să primești mesaje fără o rețea mobilă sau Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Poți să trimiți și să primești mesaje și să folosești date limitate prin satelit"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Folosești mesajele prin satelit?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Trimite și primește mesaje fără o rețea mobilă sau Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Deschide Mesaje"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 1efa10593edc..85177030d45a 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -2461,8 +2461,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Для безопасности содержимое приложения при демонстрации экрана скрыто."</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Автоматически подключено к системам спутниковой связи"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Вы можете отправлять и получать сообщения без доступа к мобильной сети или Wi-Fi."</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Вы можете обмениваться сообщениями и использовать ограниченный объем трафика по спутниковой связи."</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Включить спутниковый обмен сообщениями?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Отправляйте и получайте сообщения без подключения к мобильной сети или Wi-Fi."</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Открыть Сообщения"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 57f89a230384..863f0cc18ff8 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -302,8 +302,7 @@ <string name="notification_channel_network_alerts" msgid="6312366315654526528">"ජාල ඇඟවීම්"</string> <string name="notification_channel_network_available" msgid="6083697929214165169">"ජාලය ලබා ගැනීමට හැකිය"</string> <string name="notification_channel_vpn" msgid="1628529026203808999">"VPN තත්ත්වය"</string> - <!-- no translation found for notification_channel_system_time (1660313368058030441) --> - <skip /> + <string name="notification_channel_system_time" msgid="1660313368058030441">"වේලාව සහ කාල කලාප"</string> <string name="notification_channel_device_admin" msgid="6384932669406095506">"ඔබේ තොරතුරු තාක්ෂණ පරිපාලක වෙතින් ඇඟවීම්"</string> <string name="notification_channel_alerts" msgid="5070241039583668427">"ඇඟවීම්"</string> <string name="notification_channel_retail_mode" msgid="3732239154256431213">"සිල්ලර ආදර්ශනය"</string> @@ -311,8 +310,7 @@ <string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"යෙදුම ධාවනය කරමින්"</string> <string name="notification_channel_foreground_service" msgid="7102189948158885178">"බැටරිය භාවිත කරන යෙදුම්"</string> <string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"විශාලනය"</string> - <!-- no translation found for notification_channel_accessibility_hearing_device (7816963856388758952) --> - <skip /> + <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"ශ්රවණ උපාංගය"</string> <string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"ප්රවේශ්යතා භාවිතය"</string> <string name="notification_channel_display" msgid="6905032605735615090">"සංදර්ශකය"</string> <string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> බැටරිය භාවිත කරයි"</string> @@ -1410,10 +1408,8 @@ <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"යෙදුම බාගන්න"</string> <string name="carrier_app_notification_title" msgid="5815477368072060250">"නව SIM ඇතුළු කරන්න"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"එය පිහිටුවීමට තට්ටු කරන්න"</string> - <!-- no translation found for time_zone_change_notification_title (5232503069219193218) --> - <skip /> - <!-- no translation found for time_zone_change_notification_body (6135793674904665585) --> - <skip /> + <string name="time_zone_change_notification_title" msgid="5232503069219193218">"ඔබේ වේලා කලාපය වෙනස් විය"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"ඔබ දැන් <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) හි වේ"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"වේලාව සකසන්න"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"දිනය සැකසීම"</string> <string name="date_time_set" msgid="4603445265164486816">"සකසන්න"</string> @@ -1801,18 +1797,12 @@ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"ඔබ මෙම කෙටිමඟ භාවිතා කරන මීළඟ වතාවේ විශේෂාංගය විවෘත වනු ඇත. ඔබේ තිරයෙහි පහළ සිට ඇඟිලි 2කින් ඉහළට ස්වයිප් කර ඉක්මනින් නිදහස් කරන්න."</string> <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"ඔබ මෙම කෙටිමඟ භාවිතා කරන මීළඟ වතාවේ විශේෂාංගය විවෘත වනු ඇත. ඔබේ තිරයෙහි පහළ සිට ඇඟිලි 3කින් ඉහළට ස්වයිප් කර ඉක්මනින් නිදහස් කරන්න."</string> <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"විශාලනය"</string> - <!-- no translation found for hearing_device_switch_phone_mic_notification_title (6645178038359708836) --> - <skip /> - <!-- no translation found for hearing_device_switch_hearing_mic_notification_title (4612074852145289569) --> - <skip /> - <!-- no translation found for hearing_device_switch_phone_mic_notification_text (1332426273666077412) --> - <skip /> - <!-- no translation found for hearing_device_switch_hearing_mic_notification_text (8288368365767284208) --> - <skip /> - <!-- no translation found for hearing_device_notification_switch_button (3619524619430941300) --> - <skip /> - <!-- no translation found for hearing_device_notification_settings_button (6673651052880279178) --> - <skip /> + <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"දුරකථන මයික්රෆෝනයට මාරු වෙන්න ද?"</string> + <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"ශ්රවණාධාර මයික්රෆෝනයට මාරු වෙන්න ද?"</string> + <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"වඩා හොඳ ශබ්දයක් සඳහා හෝ ඔබේ ශ්රවණාධාර බැටරිය අඩු නම්. මෙය ඇමතුම අතරතුර පමණක් ඔබේ මයික්රෆෝනය මාරු කරයි."</string> + <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"දෑත් නොයොදන ඇමතුම් සඳහා ඔබට ඔබේ ශ්රවණාධාර මයික්රෆෝනය භාවිතා කළ හැක. මෙය ඇමතුම අතරතුර පමණක් ඔබේ මයික්රෆෝනය මාරු කරයි."</string> + <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"මාරු කරන්න"</string> + <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"සැකසීම්"</string> <string name="user_switched" msgid="7249833311585228097">"දැනට සිටින පරිශීලකයා <xliff:g id="NAME">%1$s</xliff:g>."</string> <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> වෙත මාරු කරමින්…"</string> <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> වරමින්…"</string> @@ -2469,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ආරක්ෂාව සඳහා යෙදුම් අන්තර්ගතය තිරය බෙදා ගැනීමෙන් සඟවා ඇත"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"චන්ද්රිකාවට ස්වයංක්රීයව සම්බන්ධ වේ"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"ඔබට ජංගම හෝ Wi-Fi ජාලයක් නොමැතිව පණිවිඩ යැවීමට සහ ලැබීමට හැක"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"ඔබට චන්ද්රිකා භාවිතයෙන් පණිවිඩ යැවීමට සහ ලැබීමට සහ සීමිත දත්ත භාවිතා කිරීමට හැක"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"චන්ද්රිකා පණිවිඩ යැවීම භාවිතා කරන්න ද?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"ජංගම හෝ Wi-Fi ජාලයකින් තොරව පණිවිඩ යැවීම සහ ලැබීම"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages විවෘත කරන්න"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index c50773d594a9..fbb57ca0cb74 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -2461,8 +2461,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikácie je z bezpečnostných dôvodov pri zdieľaní obrazovky skrytý"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automaticky pripojené k satelitu"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Správy môžete odosielať a prijímať bez mobilnej siete či siete Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Môžete odosielať a prijímať správy a používať obmedzené dáta cez satelit"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Chcete používať správy cez satelit?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Odosielajte a prijímajte správy bez mobilnej siete či siete Wi‑Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvoriť Správy"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 134ee9df3f3d..f7a25e9288b6 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -2461,8 +2461,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Pri deljenju zaslona je vsebina aplikacije skrita zaradi varnosti"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Samodejno vzpostavljena povezava s satelitom"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Sporočila SMS lahko pošiljate in prejemate brez mobilnega omrežja ali omrežja Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Prek satelita lahko pošiljate in prejemate sporočila ter uporabljate omejeno količino podatkov"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Želite uporabiti satelitsko pošiljanje sporočil?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Pošiljanje in prejemanje sporočil brez mobilnega omrežja ali omrežja Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Odpri Sporočila"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 0a87e39e16df..19be60047254 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -302,8 +302,7 @@ <string name="notification_channel_network_alerts" msgid="6312366315654526528">"Sinjalizimet e rrjetit"</string> <string name="notification_channel_network_available" msgid="6083697929214165169">"Ka rrjet të disponueshëm"</string> <string name="notification_channel_vpn" msgid="1628529026203808999">"Statusi i VPN-së"</string> - <!-- no translation found for notification_channel_system_time (1660313368058030441) --> - <skip /> + <string name="notification_channel_system_time" msgid="1660313368058030441">"Ora dhe brezat orarë"</string> <string name="notification_channel_device_admin" msgid="6384932669406095506">"Sinjalizimet nga administratori i teknologjisë së informacionit"</string> <string name="notification_channel_alerts" msgid="5070241039583668427">"Sinjalizimet"</string> <string name="notification_channel_retail_mode" msgid="3732239154256431213">"Demonstrimi i shitjes me pakicë"</string> @@ -311,8 +310,7 @@ <string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Aplikacioni është në ekzekutim"</string> <string name="notification_channel_foreground_service" msgid="7102189948158885178">"Aplikacionet që konsumojnë baterinë"</string> <string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Zmadhimi"</string> - <!-- no translation found for notification_channel_accessibility_hearing_device (7816963856388758952) --> - <skip /> + <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Pajisja ndihmëse për dëgjimin"</string> <string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Përdorimi i qasshmërisë"</string> <string name="notification_channel_display" msgid="6905032605735615090">"Ekrani"</string> <string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g> po përdor baterinë"</string> @@ -1410,10 +1408,8 @@ <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Shkarko aplikacionin"</string> <string name="carrier_app_notification_title" msgid="5815477368072060250">"Është futur kartë e re SIM"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Trokit për ta konfiguruar"</string> - <!-- no translation found for time_zone_change_notification_title (5232503069219193218) --> - <skip /> - <!-- no translation found for time_zone_change_notification_body (6135793674904665585) --> - <skip /> + <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Brezi yt orar është ndryshuar"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Tani je në <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Cakto kohën"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Vendos datën"</string> <string name="date_time_set" msgid="4603445265164486816">"Cakto"</string> @@ -1801,18 +1797,12 @@ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Veçoria do të hapet herën tjetër kur të përdorësh këtë shkurtore. Rrëshqit shpejt lart me 2 gishta nga fundi i ekranit dhe lëshoje me shpejtësi."</string> <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Veçoria do të hapet herën tjetër kur të përdorësh këtë shkurtore. Rrëshqit shpejt lart me 3 gishta nga fundi i ekranit dhe lëshoje me shpejtësi."</string> <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Zmadhimi"</string> - <!-- no translation found for hearing_device_switch_phone_mic_notification_title (6645178038359708836) --> - <skip /> - <!-- no translation found for hearing_device_switch_hearing_mic_notification_title (4612074852145289569) --> - <skip /> - <!-- no translation found for hearing_device_switch_phone_mic_notification_text (1332426273666077412) --> - <skip /> - <!-- no translation found for hearing_device_switch_hearing_mic_notification_text (8288368365767284208) --> - <skip /> - <!-- no translation found for hearing_device_notification_switch_button (3619524619430941300) --> - <skip /> - <!-- no translation found for hearing_device_notification_settings_button (6673651052880279178) --> - <skip /> + <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Dëshiron të kalosh te mikrofoni i telefonit?"</string> + <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Dëshiron të kalosh te mikrofoni i aparatit të dëgjimit?"</string> + <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Për tingull më të mirë ose nëse bateria e aparatit të dëgjimit është në nivel të ulët. Kjo vetëm ndërron mikrofonin gjatë telefonatës."</string> + <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Mund ta përdorësh mikrofonin e aparatit të dëgjimit për telefonata pa përdorur duart. Kjo vetëm ndërron mikrofonin gjatë telefonatës."</string> + <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Ndërro"</string> + <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Cilësimet"</string> <string name="user_switched" msgid="7249833311585228097">"Emri i përdoruesit aktual: <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="user_switching_message" msgid="1912993630661332336">"Po kalon në \"<xliff:g id="NAME">%1$s</xliff:g>\"…"</string> <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> po del…"</string> @@ -2469,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Përmbajtja e aplikacionit është fshehur nga ndarja e ekranit për arsye sigurie"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"U lidh automatikisht me satelitin"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Mund të dërgosh dhe të marrësh mesazhe pa një rrjet celular apo rrjet Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Mund të dërgosh dhe të marrësh mesazhe, si dhe të përdorësh të dhëna pa kufi nëpërmjet satelitit"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Të përdoret shkëmbimi i mesazheve nëpërmjet satelitit?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Dërgo dhe merr mesazhe pa një rrjet celular ose Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Hap \"Mesazhet\""</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 33150dc3c3c2..c286a65a78e7 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -2460,8 +2460,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Садржај апликације је скривен за дељење садржаја екрана због безбедности"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Аутоматски повезано са сателитом"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Можете да шаљете и примате поруке без мобилне или WiFi мреже"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Можете да шаљете и примате поруке, као и да користите ограничену количину података преко сателита"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Желите да користите сателитску размену порука?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Шаљите и примајте поруке без мобилне или WiFi мреже"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Отвори Messages"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index ceb0fe1d6654..a2fcd231854c 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av säkerhetsskäl döljs appinnehållet vid skärmdelning"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Automatiskt ansluten till satellit"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Du kan skicka och ta emot meddelanden utan mobil- eller wifi-nätverk"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Du kan skicka och ta emot meddelanden och använda begränsad data via satellit"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Vill du använda satellitmeddelanden?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Skicka och ta emot meddelanden utan ett mobil- eller wifi-nätverk"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Öppna Messages"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 58d71817a078..93233d91e0df 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Maudhui ya programu yamefichwa ili yasionekane kwenye skrini ya pamoja kwa sababu za kiusalama"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Imeunganishwa kiotomatiki na satelaiti"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Unaweza kutuma na kupokea ujumbe bila mtandao wa simu au Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Unaweza kutuma na kupokea ujumbe na kutumia kiwango kidogo cha data kupitia setilaiti"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Ungependa kutuma ujumbe kupitia setilaiti?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Tuma na upokee ujumbe bila kutumia mtandao wa simu wala Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Fungua Programu ya Messages"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 59668bbff71d..38f9175cc919 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"பாதுகாப்பிற்காக, திரைப் பகிர்வில் இருந்து ஆப்ஸ் உள்ளடக்கம் மறைக்கப்பட்டுள்ளது"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"சாட்டிலைட்டுடன் தானாக இணைக்கப்பட்டது"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"மொபைல்/வைஃபை நெட்வொர்க் இல்லாமல் நீங்கள் மெசேஜ்களை அனுப்பலாம் பெறலாம்"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"சாட்டிலைட் மூலம் நீங்கள் மெசேஜ்களை அனுப்பலாம் பெறலாம், வரம்பிடப்பட்ட டேட்டாவைப் பயன்படுத்தலாம்"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"சாட்டிலைட் மெசேஜிங்கைப் பயன்படுத்தவா?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"மொபைல்/வைஃபை நெட்வொர்க் இல்லாமல் மெசேஜ்களை அனுப்பலாம், பெறலாம்"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ஆப்ஸைத் திறக்கவும்"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 6285d776cfab..2a99f758daf7 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"సెక్యూరిటీ కోసం స్క్రీన్ షేర్ నుండి యాప్ కంటెంట్ దాచబడింది"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"శాటిలైట్కు ఆటోమేటిక్గా కనెక్ట్ చేయబడింది"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"మీరు మొబైల్ లేదా Wi-Fi నెట్వర్క్ లేకుండా మెసేజ్లను పంపవచ్చు, స్వీకరించవచ్చు"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"మీరు శాటిలైట్ సర్వీస్ ద్వారా మెసేజ్లను పంపవచ్చు, స్వీకరించవచ్చు, పరిమిత డేటాను ఉపయోగించండి"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"శాటిలైట్ మెసేజింగ్ను ఉపయోగించాలనుకుంటున్నారా?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"మొబైల్ లేదా Wi-Fi నెట్వర్క్ లేకుండా మెసేజ్లను పంపండి, స్వీకరించండి"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messagesను తెరవండి"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 557286128053..8f8252584757 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ซ่อนเนื้อหาแอปจากการแชร์หน้าจอแล้วเพื่อความปลอดภัย"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"เชื่อมต่อกับดาวเทียมโดยอัตโนมัติ"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"คุณรับส่งข้อความผ่านดาวเทียมได้โดยไม่ต้องใช้เครือข่ายมือถือหรือ Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"คุณจะรับส่งข้อความและใช้อินเทอร์เน็ตแบบจำกัดผ่านดาวเทียมได้"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"ใช้การรับส่งข้อความผ่านดาวเทียมไหม"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"รับและส่งข้อความโดยไม่ต้องใช้เครือข่ายมือถือหรือ Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"เปิด Messages"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 44832c87a3a7..092e15c5289f 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nakatago ang content ng app mula sa pagbabahagi ng screen para sa seguridad"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Awtomatikong nakakonekta sa satellite"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Puwede kang magpadala at tumanggap ng mga mensahe nang walang mobile o Wi-Fi network"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Puwede kang magpadala at tumanggap ng mga mensahe at gumamit ng limitadong data sa satellite"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Gumamit ng satellite messaging?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Magpadala at tumanggap ng mga mensahe nang walang mobile o Wi-Fi network"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Buksan ang Messages"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 1a8d373a2aa2..e04ad55e395f 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Uygulama içerikleri, güvenlik nedeniyle ekran paylaşımında gizlendi"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Uyduya otomatik olarak bağlandı"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Mobil veya kablosuz ağa bağlı olmadan mesaj alıp gönderebilirsiniz"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Uydu üzerinden mesaj gönderip alabilir ve sınırlı miktarda veri kullanabilirsiniz"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Uydu üzerinden mesajlaşma kullanılsın mı?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Mobil veya kablosuz ağ kullanmadan mesaj gönderip alın"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Mesajlar\'ı aç"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 5e6f9ec90037..a78847339b15 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -304,8 +304,7 @@ <string name="notification_channel_network_alerts" msgid="6312366315654526528">"Сповіщення мережі"</string> <string name="notification_channel_network_available" msgid="6083697929214165169">"Мережа доступна"</string> <string name="notification_channel_vpn" msgid="1628529026203808999">"Статус мережі VPN"</string> - <!-- no translation found for notification_channel_system_time (1660313368058030441) --> - <skip /> + <string name="notification_channel_system_time" msgid="1660313368058030441">"Час і часові пояси"</string> <string name="notification_channel_device_admin" msgid="6384932669406095506">"Сповіщення від ІТ-адміністратора"</string> <string name="notification_channel_alerts" msgid="5070241039583668427">"Сповіщення"</string> <string name="notification_channel_retail_mode" msgid="3732239154256431213">"Демо-режим для роздрібної торгівлі"</string> @@ -313,8 +312,7 @@ <string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"Працює додаток"</string> <string name="notification_channel_foreground_service" msgid="7102189948158885178">"Додатки, що використовують заряд акумулятора"</string> <string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"Збільшення"</string> - <!-- no translation found for notification_channel_accessibility_hearing_device (7816963856388758952) --> - <skip /> + <string name="notification_channel_accessibility_hearing_device" msgid="7816963856388758952">"Слуховий апарат"</string> <string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"Використання спеціальних можливостей"</string> <string name="notification_channel_display" msgid="6905032605735615090">"Дисплей"</string> <string name="foreground_service_app_in_background" msgid="1439289699671273555">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> використовує заряд акумулятора"</string> @@ -1412,10 +1410,8 @@ <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Завантажити додаток"</string> <string name="carrier_app_notification_title" msgid="5815477368072060250">"Вставлено нову SIM-карту"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Торкніться, щоб налаштувати"</string> - <!-- no translation found for time_zone_change_notification_title (5232503069219193218) --> - <skip /> - <!-- no translation found for time_zone_change_notification_body (6135793674904665585) --> - <skip /> + <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Часовий пояс змінено"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Ви зараз у часовому поясі \"<xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g>\" (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Установити час"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Установити дату"</string> <string name="date_time_set" msgid="4603445265164486816">"Застосувати"</string> @@ -1803,18 +1799,12 @@ <string name="accessibility_gesture_instructional_text" msgid="4133877896011098550">"Функція відкриється, коли ви наступного разу скористаєтеся цією швидкою командою. Проведіть двома пальцями вгору від низу екрана й швидко відпустіть."</string> <string name="accessibility_gesture_3finger_instructional_text" msgid="1124458279366968154">"Функція відкриється, коли ви наступного разу скористаєтеся цією швидкою командою. Проведіть трьома пальцями вгору від низу екрана й швидко відпустіть."</string> <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Збільшення"</string> - <!-- no translation found for hearing_device_switch_phone_mic_notification_title (6645178038359708836) --> - <skip /> - <!-- no translation found for hearing_device_switch_hearing_mic_notification_title (4612074852145289569) --> - <skip /> - <!-- no translation found for hearing_device_switch_phone_mic_notification_text (1332426273666077412) --> - <skip /> - <!-- no translation found for hearing_device_switch_hearing_mic_notification_text (8288368365767284208) --> - <skip /> - <!-- no translation found for hearing_device_notification_switch_button (3619524619430941300) --> - <skip /> - <!-- no translation found for hearing_device_notification_settings_button (6673651052880279178) --> - <skip /> + <string name="hearing_device_switch_phone_mic_notification_title" msgid="6645178038359708836">"Перемкнути на мікрофон телефона?"</string> + <string name="hearing_device_switch_hearing_mic_notification_title" msgid="4612074852145289569">"Перемкнути на мікрофон слухового апарата?"</string> + <string name="hearing_device_switch_phone_mic_notification_text" msgid="1332426273666077412">"Використовується, щоб покращити якість звуку або якщо акумулятор слухового апарата розряджений. Мікрофон перемикатиметься лише на час дзвінка."</string> + <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Ви можете використовувати мікрофон слухового апарата для голосового керування викликами. Мікрофон перемикатиметься лише на час дзвінка."</string> + <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Перемкнути"</string> + <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Налаштування"</string> <string name="user_switched" msgid="7249833311585228097">"Поточний користувач: <xliff:g id="NAME">%1$s</xliff:g>."</string> <string name="user_switching_message" msgid="1912993630661332336">"Перехід у режим \"<xliff:g id="NAME">%1$s</xliff:g>\"…"</string> <string name="user_logging_out_message" msgid="7216437629179710359">"Вихід з облікового запису користувача <xliff:g id="NAME">%1$s</xliff:g>…"</string> @@ -2471,8 +2461,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"З міркувань безпеки вміст додатка приховано під час показу екрана"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Автоматично підключено до супутника"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Ви можете надсилати й отримувати повідомлення, не використовуючи Wi-Fi або мобільну мережу"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Ви можете надсилати й отримувати повідомлення та використовувати обмежений обсяг даних через супутник"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Скористатися супутниковим обміном повідомленнями?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Надсилайте й отримуйте текстові повідомлення без мобільної мережі або Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Відкрийте Повідомлення"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 7ddd7cb8a02a..7f3a2ef7ed31 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"سیکیورٹی کے مد نظر ایپ کا مواد اسکرین کے اشتراک سے چھپا ہوا ہے"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"سٹلائٹ سے خودکار طور پر منسلک ہے"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"آپ موبائل یا Wi-Fi نیٹ ورک کے بغیر پیغامات بھیج اور موصول کر سکتے ہیں"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"آپ سیٹلائٹ کے ذریعے پیغامات بھیج اور موصول کر سکتے ہیں اور محدود ڈیٹا استعمال کر سکتے ہیں"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"سیٹلائٹ پیغام رسانی کا استعمال کریں؟"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"موبائل یا Wi-Fi نیٹ ورک کے بغیر پیغامات بھیجیں اور موصول کریں"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"پیغامات ایپ کو کھولیں"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index c1697953eb53..9f24b987033b 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ekran namoyishida xavfsizlik maqsadida ilova kontenti berkitildi"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Sputnikka avtomatik ulandi"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Mobil yoki Wi-Fi tarmoqsiz xabarlarni yuborishingiz va qabul qilishingiz mumkin"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Sputnik orqali xabarlar yuborish va qabul qilish hamda cheklangan trafikdan foydalanish mumkin"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Sputnik orqali xabarlashuv ishlatilsinmi?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Mobil yoki Wi-Fi tarmoq blan aloqa yoʻqligida xabar yuboring va qabul qiling"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Xabarlar ilovasini ochish"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 11b57703d339..678f3e09f123 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nội dung ứng dụng bị ẩn khỏi tính năng chia sẻ màn hình vì lý do bảo mật"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Đã tự động kết nối với vệ tinh"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Bạn có thể gửi và nhận tin nhắn mà không cần có mạng di động hoặc mạng Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Bạn có thể gửi và nhận tin nhắn cũng như sử dụng dữ liệu hạn chế qua vệ tinh"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Sử dụng tính năng nhắn tin qua vệ tinh?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Gửi và nhận tin nhắn mà không cần mạng di động hoặc Wi-Fi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Mở ứng dụng Tin nhắn"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 4a38b933b000..c5cad4bc9503 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"为安全起见,屏幕共享画面已隐藏此应用的内容"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"自动连接到卫星"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"您无需使用移动网络或 WLAN 网络便能收发消息"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"您可以使用有限的数据通过卫星收发消息"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"使用卫星消息功能?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"即使没有移动网络或 WLAN 网络,也能收发消息"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"打开“信息”应用"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index cd428895c4d0..0fb351d12681 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"為安全起見,應用程式內容已從分享螢幕畫面隱藏"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"已自動連線至衛星"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"你可在沒有流動/Wi-Fi 網絡的情況下收發訊息"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"你可透過衛星傳送和接收訊息,以及使用有限數據"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"要使用衛星訊息嗎?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"在沒有流動網絡或 Wi-Fi 網絡的情況下收發短訊"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"開啟「訊息」"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index c8ae6793a4e3..9e83ce8d44c2 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"為安全起見,分享螢幕畫面隱藏了這個應用程式的內容"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"已自動連上衛星"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"你可以收發訊息,沒有行動/Wi-Fi 網路也無妨"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"你可以透過有限的衛星數據收發訊息"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"要使用衛星訊息功能嗎?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"即使沒有行動或 Wi-Fi 網路,還是可以收發訊息"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"開啟「訊息」應用程式"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 7658189f3f55..a2827799c252 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -2459,8 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Okuqukethwe kwe-app kufihliwe kusuka ekwabelaneni kwesikrini ngokuvikelwa"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"Ixhumeke ngokuzenzakalelayo kusathelayithi"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"Ungathumela futhi wamukele imilayezo ngaphandle kwenethiwekhi yeselula noma ye-Wi-Fi"</string> - <!-- no translation found for satellite_notification_summary_with_data (6486843676720429049) --> - <skip /> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"Ungathumela futhi wamukele imiyalezo usebenzise nedatha enomkhawulo ngesathelayithi"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"Sebenzisa ukuthumela umyalezo ngesethelayithi?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"Thumela futhi wamukele imilayezo ngaphandle kwenethiwekhi yeselula noma yeWiFi"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Vula Imilayezo"</string> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 13dd4a35564c..864daf9d2072 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -582,6 +582,10 @@ <color name="side_fps_text_color">#191C1D</color> <color name="side_fps_button_color">#00677E</color> + <!-- Color for various surfaces related to system-wide blur --> + <color name="surface_effect_0">@color/surface_effect_0_color</color> + <color name="surface_effect_1">@color/surface_effect_1_color</color> + <!-- Color for system bars --> <color name="navigation_bar_compatible">@android:color/black</color> <!-- This uses non-regular transparent intentionally. It is used to tell if the transparent diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index ec1be83dcae6..b894d3a6888f 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2889,7 +2889,7 @@ <bool name="config_dozeAlwaysOnEnabled">true</bool> <!-- If AOD can show an ambient version of the wallpaper --> - <bool name="config_dozeSupportsAodWallpaper">true</bool> + <bool name="config_dozeSupportsAodWallpaper">false</bool> <!-- Whether the display blanks itself when transitioning from a doze to a non-doze state --> <bool name="config_displayBlanksAfterDoze">false</bool> @@ -7299,6 +7299,10 @@ <!-- Whether to enable fp unlock when screen turns off on udfps devices --> <bool name="config_screen_off_udfps_enabled">false</bool> + <!-- Default value for fp screen off unlock toggle, it only works for the devices that support + fp screen off unlock--> + <bool name="config_screen_off_udfps_default_on">false</bool> + <!-- The name of the system package that will hold the dependency installer role. --> <string name="config_systemDependencyInstaller" translatable="false" /> diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index 7baaa6d590f2..a0c4c13a8702 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -137,6 +137,14 @@ <public name="wantsRoleHolderPriority"/> <!-- @FlaggedApi(android.sdk.Flags.FLAG_MAJOR_MINOR_VERSIONING_SCHEME) --> <public name="minSdkVersionFull"/> + <!-- @hide Only for device overlay to use this. --> + <public name="pointerIconVectorFill"/> + <!-- @hide Only for device overlay to use this. --> + <public name="pointerIconVectorFillInverse"/> + <!-- @hide Only for device overlay to use this. --> + <public name="pointerIconVectorStroke"/> + <!-- @hide Only for device overlay to use this. --> + <public name="pointerIconVectorStrokeInverse"/> </staging-public-group> <staging-public-group type="id" first-id="0x01b60000"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 77cc6868bd58..8315e3cf1a11 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -532,6 +532,8 @@ <java-symbol type="bool" name="config_enableUdcSysfsUsbStateUpdate"/> <java-symbol type="bool" name="config_enableSearchTileHideIllustrationInPrivateSpace"/> + <java-symbol type="color" name="surface_effect_0" /> + <java-symbol type="color" name="surface_effect_1" /> <java-symbol type="color" name="tab_indicator_text_v4" /> <java-symbol type="dimen" name="accessibility_touch_slop" /> @@ -5791,6 +5793,9 @@ <!-- Fingerprint screen off unlock config --> <java-symbol type="bool" name="config_screen_off_udfps_enabled" /> + <!-- Default toggle for fp screen of unlcok--> + <java-symbol type="bool" name="config_screen_off_udfps_default_on" /> + <!-- Style for Wear Material3 Button. Will only be used for sdk 36 or above. --> <java-symbol type="style" name="Widget.DeviceDefault.Button.WearMaterial3" /> diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index c40137f1bd34..cef6970ba25a 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -1054,7 +1054,8 @@ public class ViewRootImplTest { ViewRootImpl viewRootImpl = mView.getViewRootImpl(); sInstrumentation.runOnMainSync(() -> { mView.invalidate(); - viewRootImpl.notifyInsetsAnimationRunningStateChanged(true); + viewRootImpl.notifyInsetsAnimationRunningStateChanged(true, 0 /* animationType */, + 0 /* insetsTypes */ /* areOtherAnimationsRunning */); mView.invalidate(); }); sInstrumentation.waitForIdleSync(); diff --git a/core/tests/coretests/src/android/window/DesktopModeFlagsTest.java b/core/tests/coretests/src/android/window/DesktopModeFlagsTest.java index b28e2b04b342..49927be65ae5 100644 --- a/core/tests/coretests/src/android/window/DesktopModeFlagsTest.java +++ b/core/tests/coretests/src/android/window/DesktopModeFlagsTest.java @@ -21,33 +21,42 @@ import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF; import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_ON; import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET; import static android.window.DesktopModeFlags.ToggleOverride.fromSetting; -import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TRANSITIONS; import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE; -import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS; +import static com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_EXPERIENCE_DEV_OPTION; import static com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assume.assumeTrue; + import android.content.ContentResolver; import android.content.Context; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.FlagsParameterization; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; +import android.support.test.uiautomator.UiDevice; +import android.window.DesktopModeFlags.DesktopModeFlag; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.window.flags.Flags; + import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + import java.lang.reflect.Field; +import java.util.List; /** * Test class for {@link android.window.DesktopModeFlags} @@ -57,21 +66,39 @@ import java.lang.reflect.Field; */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) +@RunWith(ParameterizedAndroidJunit4.class) public class DesktopModeFlagsTest { + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return FlagsParameterization.allCombinationsOf(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, + FLAG_SHOW_DESKTOP_EXPERIENCE_DEV_OPTION); + } + @Rule - public SetFlagsRule setFlagsRule = new SetFlagsRule(); + public SetFlagsRule mSetFlagsRule; + private UiDevice mUiDevice; private Context mContext; + private boolean mLocalFlagValue = false; + private final DesktopModeFlag mOverriddenLocalFlag = new DesktopModeFlag( + () -> mLocalFlagValue, true); + private final DesktopModeFlag mNotOverriddenLocalFlag = new DesktopModeFlag( + () -> mLocalFlagValue, false); private static final int OVERRIDE_OFF_SETTING = 0; private static final int OVERRIDE_ON_SETTING = 1; private static final int OVERRIDE_UNSET_SETTING = -1; + public DesktopModeFlagsTest(FlagsParameterization flags) { + mSetFlagsRule = new SetFlagsRule(flags); + } + @Before - public void setUp() { + public void setUp() throws Exception { mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + setOverride(null); } @After @@ -80,26 +107,35 @@ public class DesktopModeFlagsTest { } @Test - @DisableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - public void isTrue_devOptionFlagDisabled_overrideOff_featureFlagOn_returnsTrue() { + public void isTrue_overrideOff_featureFlagOn() throws Exception { setOverride(OVERRIDE_OFF_SETTING); - // In absence of dev options, follow flag - assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isTrue(); + + if (showDesktopWindowingDevOpts()) { + // DW Dev Opts turns off flags when ON + assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isFalse(); + } else { + // DE Dev Opts doesn't turn flags OFF + assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isTrue(); + } } @Test - @DisableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) - public void isTrue_devOptionFlagDisabled_overrideOn_featureFlagOff_returnsFalse() { + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_overrideOn_featureFlagOff() throws Exception { setOverride(OVERRIDE_ON_SETTING); - assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isFalse(); + if (showAnyDevOpts()) { + assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isTrue(); + } else { + assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isFalse(); + } } @Test - @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) - public void isTrue_overrideUnset_featureFlagOn_returnsTrue() { + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_overrideUnset_featureFlagOn() throws Exception { setOverride(OVERRIDE_UNSET_SETTING); // For overridableFlag, for unset overrides, follow flag @@ -107,9 +143,8 @@ public class DesktopModeFlagsTest { } @Test - @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - public void isTrue_overrideUnset_featureFlagOff_returnsFalse() { + public void isTrue_overrideUnset_featureFlagOff() throws Exception { setOverride(OVERRIDE_UNSET_SETTING); // For overridableFlag, for unset overrides, follow flag @@ -117,8 +152,8 @@ public class DesktopModeFlagsTest { } @Test - @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) - public void isTrue_noOverride_featureFlagOn_returnsTrue() { + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_noOverride_featureFlagOn_returnsTrue() throws Exception { setOverride(null); // For overridableFlag, in absence of overrides, follow flag @@ -126,9 +161,8 @@ public class DesktopModeFlagsTest { } @Test - @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - public void isTrue_noOverride_featureFlagOff_returnsFalse() { + public void isTrue_noOverride_featureFlagOff_returnsFalse() throws Exception { setOverride(null); // For overridableFlag, in absence of overrides, follow flag @@ -136,8 +170,8 @@ public class DesktopModeFlagsTest { } @Test - @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) - public void isTrue_unrecognizableOverride_featureFlagOn_returnsTrue() { + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_unrecognizableOverride_featureFlagOn_returnsTrue() throws Exception { setOverride(-2); // For overridableFlag, for unrecognized overrides, follow flag @@ -145,9 +179,8 @@ public class DesktopModeFlagsTest { } @Test - @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - public void isTrue_unrecognizableOverride_featureFlagOff_returnsFalse() { + public void isTrue_unrecognizableOverride_featureFlagOff_returnsFalse() throws Exception { setOverride(-2); // For overridableFlag, for unrecognizable overrides, follow flag @@ -155,27 +188,10 @@ public class DesktopModeFlagsTest { } @Test - @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) - public void isTrue_overrideOff_featureFlagOn_returnsFalse() { - setOverride(OVERRIDE_OFF_SETTING); - - // For overridableFlag, follow override if they exist - assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isFalse(); - } - - @Test - @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) - @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - public void isTrue_overrideOn_featureFlagOff_returnsTrue() { - setOverride(OVERRIDE_ON_SETTING); - - // For overridableFlag, follow override if they exist - assertThat(ENABLE_DESKTOP_WINDOWING_MODE.isTrue()).isTrue(); - } + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() throws Exception { + assumeTrue(showDesktopWindowingDevOpts()); - @Test - @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) - public void isTrue_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() { setOverride(OVERRIDE_OFF_SETTING); // For overridableFlag, follow override if they exist @@ -188,9 +204,9 @@ public class DesktopModeFlagsTest { } @Test - @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - public void isTrue_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() { + public void isTrue_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() throws Exception { + assumeTrue(showAnyDevOpts()); setOverride(OVERRIDE_ON_SETTING); // For overridableFlag, follow override if they exist @@ -203,146 +219,144 @@ public class DesktopModeFlagsTest { } @Test - @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE, - FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS}) - public void isTrue_dwFlagOn_overrideUnset_featureFlagOn_returnsTrue() { + @EnableFlags({FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isTrue_dwFlagOn_overrideUnset_featureFlagOn() throws Exception { + mLocalFlagValue = true; setOverride(OVERRIDE_UNSET_SETTING); // For unset overrides, follow flag - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue(); + assertThat(mOverriddenLocalFlag.isTrue()).isTrue(); + assertThat(mNotOverriddenLocalFlag.isTrue()).isTrue(); } @Test - @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) - @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS) - public void isTrue_dwFlagOn_overrideUnset_featureFlagOff_returnsFalse() { + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_dwFlagOn_overrideUnset_featureFlagOff() throws Exception { + mLocalFlagValue = false; setOverride(OVERRIDE_UNSET_SETTING); // For unset overrides, follow flag - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse(); + assertThat(mOverriddenLocalFlag.isTrue()).isFalse(); + assertThat(mNotOverriddenLocalFlag.isTrue()).isFalse(); } @Test - @EnableFlags({ - FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, - FLAG_ENABLE_DESKTOP_WINDOWING_MODE, - FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS - }) - public void isTrue_dwFlagOn_overrideOn_featureFlagOn_returnsTrue() { + @EnableFlags({FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) + public void isTrue_dwFlagOn_overrideOn_featureFlagOn() throws Exception { + mLocalFlagValue = true; setOverride(OVERRIDE_ON_SETTING); // When toggle override matches its default state (dw flag), don't override flags - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue(); + assertThat(mOverriddenLocalFlag.isTrue()).isTrue(); + assertThat(mNotOverriddenLocalFlag.isTrue()).isTrue(); } @Test - @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) - @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS) - public void isTrue_dwFlagOn_overrideOn_featureFlagOff_returnsFalse() { + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_dwFlagOn_overrideOn_featureFlagOff() throws Exception { + mLocalFlagValue = false; setOverride(OVERRIDE_ON_SETTING); - // When toggle override matches its default state (dw flag), don't override flags - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse(); + if (showDesktopExperienceDevOpts()) { + assertThat(mOverriddenLocalFlag.isTrue()).isTrue(); + } else { + assertThat(mOverriddenLocalFlag.isTrue()).isFalse(); + } + assertThat(mNotOverriddenLocalFlag.isTrue()).isFalse(); } @Test - @EnableFlags({ - FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, - FLAG_ENABLE_DESKTOP_WINDOWING_MODE, - FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS - }) - public void isTrue_dwFlagOn_overrideOff_featureFlagOn_returnsTrue() { + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_dwFlagOn_overrideOff_featureFlagOn() throws Exception { + mLocalFlagValue = true; setOverride(OVERRIDE_OFF_SETTING); - // Follow override if they exist, and is not equal to default toggle state (dw flag) - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue(); + if (showDesktopWindowingDevOpts()) { + // Follow override if they exist, and is not equal to default toggle state (dw flag) + assertThat(mOverriddenLocalFlag.isTrue()).isFalse(); + } else { + assertThat(mOverriddenLocalFlag.isTrue()).isTrue(); + } + assertThat(mNotOverriddenLocalFlag.isTrue()).isTrue(); } @Test - @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE}) - @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS) - public void isTrue_dwFlagOn_overrideOff_featureFlagOff_returnsFalse() { + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_dwFlagOn_overrideOff_featureFlagOff_returnsFalse() throws Exception { + mLocalFlagValue = false; setOverride(OVERRIDE_OFF_SETTING); // Follow override if they exist, and is not equal to default toggle state (dw flag) - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse(); + assertThat(mOverriddenLocalFlag.isTrue()).isFalse(); + assertThat(mNotOverriddenLocalFlag.isTrue()).isFalse(); } @Test - @EnableFlags({ - FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, - FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS - }) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - public void isTrue_dwFlagOff_overrideUnset_featureFlagOn_returnsTrue() { + public void isTrue_dwFlagOff_overrideUnset_featureFlagOn_returnsTrue() throws Exception { + mLocalFlagValue = true; setOverride(OVERRIDE_UNSET_SETTING); // For unset overrides, follow flag - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue(); + assertThat(mOverriddenLocalFlag.isTrue()).isTrue(); + assertThat(mNotOverriddenLocalFlag.isTrue()).isTrue(); } @Test - @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) - @DisableFlags({ - FLAG_ENABLE_DESKTOP_WINDOWING_MODE, - FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS - }) - public void isTrue_dwFlagOff_overrideUnset_featureFlagOff_returnsFalse() { + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_dwFlagOff_overrideUnset_featureFlagOff_returnsFalse() throws Exception { + mLocalFlagValue = false; setOverride(OVERRIDE_UNSET_SETTING); // For unset overrides, follow flag - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse(); + assertThat(mOverriddenLocalFlag.isTrue()).isFalse(); + assertThat(mNotOverriddenLocalFlag.isTrue()).isFalse(); } @Test - @EnableFlags({ - FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, - FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS - }) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - public void isTrue_dwFlagOff_overrideOn_featureFlagOn_returnsTrue() { + public void isTrue_dwFlagOff_overrideOn_featureFlagOn_returnsTrue() throws Exception { + mLocalFlagValue = true; setOverride(OVERRIDE_ON_SETTING); // Follow override if they exist, and is not equal to default toggle state (dw flag) - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue(); + assertThat(mOverriddenLocalFlag.isTrue()).isTrue(); + assertThat(mNotOverriddenLocalFlag.isTrue()).isTrue(); } @Test - @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) - @DisableFlags({ - FLAG_ENABLE_DESKTOP_WINDOWING_MODE, - FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS - }) - public void isTrue_dwFlagOff_overrideOn_featureFlagOff_returnFalse() { + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_dwFlagOff_overrideOn_featureFlagOff() throws Exception { + mLocalFlagValue = false; setOverride(OVERRIDE_ON_SETTING); - // Follow override if they exist, and is not equal to default toggle state (dw flag) - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse(); + if (showAnyDevOpts()) { + assertThat(mOverriddenLocalFlag.isTrue()).isTrue(); + } else { + // Follow override if they exist, and is not equal to default toggle state (dw flag) + assertThat(mOverriddenLocalFlag.isTrue()).isFalse(); + } + assertThat(mNotOverriddenLocalFlag.isTrue()).isFalse(); } @Test - @EnableFlags({ - FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, - FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS - }) @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) - public void isTrue_dwFlagOff_overrideOff_featureFlagOn_returnsTrue() { + public void isTrue_dwFlagOff_overrideOff_featureFlagOn_returnsTrue() throws Exception { + mLocalFlagValue = true; setOverride(OVERRIDE_OFF_SETTING); // When toggle override matches its default state (dw flag), don't override flags - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isTrue(); + assertThat(mOverriddenLocalFlag.isTrue()).isTrue(); + assertThat(mNotOverriddenLocalFlag.isTrue()).isTrue(); } @Test - @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) - @DisableFlags({ - FLAG_ENABLE_DESKTOP_WINDOWING_MODE, - FLAG_ENABLE_DESKTOP_WINDOWING_TRANSITIONS - }) - public void isTrue_dwFlagOff_overrideOff_featureFlagOff_returnsFalse() { + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void isTrue_dwFlagOff_overrideOff_featureFlagOff_returnsFalse() throws Exception { + mLocalFlagValue = false; setOverride(OVERRIDE_OFF_SETTING); - // When toggle override matches its default state (dw flag), don't override flags - assertThat(ENABLE_DESKTOP_WINDOWING_TRANSITIONS.isTrue()).isFalse(); + assertThat(mOverriddenLocalFlag.isTrue()).isFalse(); + assertThat(mNotOverriddenLocalFlag.isTrue()).isFalse(); } @Test @@ -365,7 +379,9 @@ public class DesktopModeFlagsTest { assertThat(OVERRIDE_UNSET.getSetting()).isEqualTo(-1); } - private void setOverride(Integer setting) { + private void setOverride(Integer setting) throws Exception { + setSysProp(setting); + ContentResolver contentResolver = mContext.getContentResolver(); String key = Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES; @@ -376,11 +392,35 @@ public class DesktopModeFlagsTest { } } + private void setSysProp(Integer value) throws Exception { + if (value == null) { + resetSysProp(); + } else { + mUiDevice.executeShellCommand( + "setprop " + DesktopModeFlags.SYSTEM_PROPERTY_NAME + " " + value); + } + } + + private void resetSysProp() throws Exception { + mUiDevice.executeShellCommand("setprop " + DesktopModeFlags.SYSTEM_PROPERTY_NAME + " ''"); + } + private void resetCache() throws Exception { Field cachedToggleOverride = DesktopModeFlags.class.getDeclaredField( "sCachedToggleOverride"); cachedToggleOverride.setAccessible(true); cachedToggleOverride.set(null, null); - setOverride(OVERRIDE_UNSET_SETTING); + } + + private boolean showDesktopWindowingDevOpts() { + return Flags.showDesktopWindowingDevOption() && !Flags.showDesktopExperienceDevOption(); + } + + private boolean showDesktopExperienceDevOpts() { + return Flags.showDesktopExperienceDevOption(); + } + + private boolean showAnyDevOpts() { + return Flags.showDesktopWindowingDevOption() || Flags.showDesktopExperienceDevOption(); } } diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java index d898d222b8de..36c73e2e979e 100644 --- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java +++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java @@ -187,6 +187,9 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { shell("cmd overlay list " + APP_OVERLAY_PACKAGE_NAME).trim()); assertEquals("STATE_ENABLED", shell("cmd overlay dump state " + APP_OVERLAY_PACKAGE_NAME).trim()); + + assertEquals("STATE_ENABLED", + shell("cmd overlay dump --user current state " + APP_OVERLAY_PACKAGE_NAME).trim()); } private void delay() { diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml index 45952ea75b6f..3eadf3b94515 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -95,5 +95,6 @@ <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND" /> <permission name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW"/> <permission name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" /> + <permission name="android.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION" /> </privapp-permissions> </permissions> diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index b332cf0d751f..3d4dccf095f5 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -2198,10 +2198,12 @@ public class Paint { * is configured as {@code 'wght' 500, 'ital' 1}, and if the override is specified as * {@code 'wght' 700, `wdth` 150}, then the effective font variation setting is * {@code `wght' 700, 'ital' 1, 'wdth' 150}. The `wght` value is updated by override, 'ital' - * value is preserved because no overrides, and `wdth` value is added by override. + * value is preserved because no overrides, and `wdth` value is added by override. If the font + * variation override is empty or null, nothing overrides and original font variation settings + * assigned to the font instance is used as it is. * - * @param fontVariationOverride font variation settings. You can pass null or empty string as - * no variation settings. + * @param fontVariationOverride font variation override. You can pass null or empty string for + * clearing font variation override. * * @return true if the provided font variation settings is valid. Otherwise returns false. * diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index d0d1721115cb..1bcb0bb91515 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -18,6 +18,7 @@ package androidx.window.extensions.embedding; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; @@ -3154,15 +3155,22 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen final WindowContainerTransaction wct = transactionRecord.getTransaction(); final TaskFragmentContainer launchedInTaskFragment; if (launchingActivity != null) { - final int taskId = getTaskId(launchingActivity); final String overlayTag = options.getString(KEY_OVERLAY_TAG); if (Flags.activityEmbeddingOverlayPresentationFlag() && overlayTag != null) { launchedInTaskFragment = createOrUpdateOverlayTaskFragmentIfNeeded(wct, options, intent, launchingActivity); } else { - launchedInTaskFragment = resolveStartActivityIntent(wct, taskId, intent, - launchingActivity); + final int taskId = getTaskId(launchingActivity); + if (taskId != INVALID_TASK_ID) { + launchedInTaskFragment = resolveStartActivityIntent(wct, taskId, intent, + launchingActivity); + } else { + // We cannot get a valid task id of launchingActivity so we fall back to + // treat it as a non-Activity context. + launchedInTaskFragment = + resolveStartActivityIntentFromNonActivityContext(wct, intent); + } } } else { launchedInTaskFragment = resolveStartActivityIntentFromNonActivityContext(wct, diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig index e4210261a9fc..065644627393 100644 --- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig +++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig @@ -5,12 +5,6 @@ package: "com.android.wm.shell" container: "system" -flag { - name: "enable_app_pairs" - namespace: "multitasking" - description: "Enables the ability to create and save app pairs to the Home screen" - bug: "274835596" -} flag { name: "enable_taskbar_navbar_unification" @@ -27,13 +21,6 @@ flag { } flag { - name: "enable_left_right_split_in_portrait" - namespace: "multitasking" - description: "Enables left/right split in portrait" - bug: "291018646" -} - -flag { name: "enable_new_bubble_animations" namespace: "multitasking" description: "Enables new animations for expand and collapse for bubbles" diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml index eb50ba7c9477..f9a3c355773c 100644 --- a/libs/WindowManager/Shell/res/values-fa/strings.xml +++ b/libs/WindowManager/Shell/res/values-fa/strings.xml @@ -79,7 +79,7 @@ <string name="bubbles_user_education_description" msgid="4215862563054175407">"مکالمههای جدید بهصورت نمادهای شناور یا حبابکها نشان داده میشوند. برای باز کردن حبابکها تکضرب بزنید. برای جابهجایی، آن را بکشید."</string> <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"کنترل حبابکها در هرزمانی"</string> <string name="bubbles_user_education_manage" msgid="3460756219946517198">"برای خاموش کردن حبابکها از این برنامه، روی «مدیریت» تکضرب بزنید"</string> - <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"متوجهام"</string> + <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"متوجهم"</string> <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"هیچ حبابک جدیدی وجود ندارد"</string> <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"حبابکهای اخیر و حبابکهای ردشده اینجا ظاهر خواهند شد"</string> <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"گپ زدن بااستفاده از حبابک"</string> @@ -103,7 +103,7 @@ <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"از چندین برنامه بهطور همزمان استفاده کنید"</string> <string name="letterbox_education_split_screen_text" msgid="449233070804658627">"برای حالت صفحهٔ دونیمه، در برنامهای دیگر بکشید"</string> <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"برای جابهجا کردن برنامه، بیرون از آن دو تکضرب بزنید"</string> - <string name="letterbox_education_got_it" msgid="4057634570866051177">"متوجهام"</string> + <string name="letterbox_education_got_it" msgid="4057634570866051177">"متوجهم"</string> <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"برای اطلاعات بیشتر، گسترده کنید."</string> <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"برای نمایش بهتر بازراهاندازی شود؟"</string> <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"میتوانید برنامه را بازراهاندازی کنید تا بهتر روی صفحهنمایش نشان داده شود، اما ممکن است پیشرفت یا تغییرات ذخیرهنشده را ازدست بدهید"</string> diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java index 2fed1380b635..1ee71ca78815 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java @@ -218,6 +218,13 @@ public class DesktopModeStatus { return isDeviceEligibleForDesktopMode(context) && Flags.showDesktopWindowingDevOption(); } + /** + * Return {@code true} if desktop mode dev option should be shown on current device + */ + public static boolean canShowDesktopExperienceDevOption(@NonNull Context context) { + return Flags.showDesktopExperienceDevOption(); + } + /** Returns if desktop mode dev option should be enabled if there is no user override. */ public static boolean shouldDevOptionBeEnabledByDefault() { return Flags.enableDesktopWindowingMode(); @@ -290,7 +297,7 @@ public class DesktopModeStatus { /** * Return {@code true} if desktop mode is unrestricted and is supported in the device. */ - private static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) { + public static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) { return !enforceDeviceRestrictions() || isDesktopModeSupported(context); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStack.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStack.kt deleted file mode 100644 index caacdd355996..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStack.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.automotive - -import android.app.ActivityManager -import android.graphics.Rect -import android.view.SurfaceControl - -/** - * Represents an auto task stack, which is always in multi-window mode. - * - * @property id The ID of the task stack. - * @property displayId The ID of the display the task stack is on. - * @property leash The surface control leash of the task stack. - */ -interface AutoTaskStack { - val id: Int - val displayId: Int - var leash: SurfaceControl -} - -/** - * Data class representing the state of an auto task stack. - * - * @property bounds The bounds of the task stack. - * @property childrenTasksVisible Whether the child tasks of the stack are visible. - * @property layer The layer of the task stack. - */ -data class AutoTaskStackState( - val bounds: Rect = Rect(), - val childrenTasksVisible: Boolean, - val layer: Int -) - -/** - * Data class representing a root task stack. - * - * @property id The ID of the root task stack - * @property displayId The ID of the display the root task stack is on. - * @property leash The surface control leash of the root task stack. - * @property rootTaskInfo The running task info of the root task. - */ -data class RootTaskStack( - override val id: Int, - override val displayId: Int, - override var leash: SurfaceControl, - var rootTaskInfo: ActivityManager.RunningTaskInfo -) : AutoTaskStack diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStackController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStackController.kt deleted file mode 100644 index 15fedac62af3..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStackController.kt +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.automotive - -import android.app.PendingIntent -import android.content.Intent -import android.os.Bundle -import android.os.IBinder -import android.view.SurfaceControl -import android.window.TransitionInfo -import android.window.TransitionRequestInfo -import com.android.wm.shell.shared.annotations.ShellMainThread -import com.android.wm.shell.transition.Transitions -import com.android.wm.shell.transition.Transitions.TransitionFinishCallback - -/** - * Delegate interface for handling auto task stack transitions. - */ -interface AutoTaskStackTransitionHandlerDelegate { - /** - * Handles a transition request. - * - * @param transition The transition identifier. - * @param request The transition request information. - * @return An [AutoTaskStackTransaction] to be applied for the transition, or null if the - * animation is not handled by this delegate. - */ - fun handleRequest( - transition: IBinder, request: TransitionRequestInfo - ): AutoTaskStackTransaction? - - /** - * See [Transitions.TransitionHandler.startAnimation] for more details. - * - * @param changedTaskStacks Contains the states of the task stacks that were changed as a - * result of this transition. The key is the [AutoTaskStack.id] and the value is the - * corresponding [AutoTaskStackState]. - */ - fun startAnimation( - transition: IBinder, - changedTaskStacks: Map<Int, AutoTaskStackState>, - info: TransitionInfo, - startTransaction: SurfaceControl.Transaction, - finishTransaction: SurfaceControl.Transaction, - finishCallback: TransitionFinishCallback - ): Boolean - - /** - * See [Transitions.TransitionHandler.onTransitionConsumed] for more details. - * - * @param requestedTaskStacks contains the states of the task stacks that were requested in - * the transition. The key is the [AutoTaskStack.id] and the value is the corresponding - * [AutoTaskStackState]. - */ - fun onTransitionConsumed( - transition: IBinder, - requestedTaskStacks: Map<Int, AutoTaskStackState>, - aborted: Boolean, finishTransaction: SurfaceControl.Transaction? - ) - - /** - * See [Transitions.TransitionHandler.mergeAnimation] for more details. - * - * @param changedTaskStacks Contains the states of the task stacks that were changed as a - * result of this transition. The key is the [AutoTaskStack.id] and the value is the - * corresponding [AutoTaskStackState]. - */ - fun mergeAnimation( - transition: IBinder, - changedTaskStacks: Map<Int, AutoTaskStackState>, - info: TransitionInfo, - surfaceTransaction: SurfaceControl.Transaction, - mergeTarget: IBinder, - finishCallback: TransitionFinishCallback - ) -} - - -/** - * Controller for managing auto task stacks. - */ -interface AutoTaskStackController { - - var autoTransitionHandlerDelegate: AutoTaskStackTransitionHandlerDelegate? - set - - /** - * Map of task stack IDs to their states. - * - * This gets updated right before [AutoTaskStackTransitionHandlerDelegate.startAnimation] or - * [AutoTaskStackTransitionHandlerDelegate.onTransitionConsumed] is called. - */ - val taskStackStateMap: Map<Int, AutoTaskStackState> - get - - /** - * Creates a new multi-window root task. - * - * A root task stack is placed in the default TDA of the specified display by default. - * Once the root task is removed, the [AutoTaskStackController] no longer holds a reference to - * it. - * - * @param displayId The ID of the display to create the root task stack on. - * @param listener The listener for root task stack events. - */ - @ShellMainThread - fun createRootTaskStack(displayId: Int, listener: RootTaskStackListener) - - - /** - * Sets the default root task stack (launch root) on a display. Calling it again with a - * different [rootTaskStackId] will simply replace the default root task stack on the display. - * - * Note: This is helpful for passively routing tasks to a specified container. If a display - * doesn't have a default root task stack set, all tasks will open in fullscreen and cover - * the entire default TDA by default. - * - * @param displayId The ID of the display. - * @param rootTaskStackId The ID of the root task stack, or null to clear the default. - */ - @ShellMainThread - fun setDefaultRootTaskStackOnDisplay(displayId: Int, rootTaskStackId: Int?) - - /** - * Starts a transaction with the specified [transaction]. - * Returns the transition identifier. - */ - @ShellMainThread - fun startTransition(transaction: AutoTaskStackTransaction): IBinder? -} - -internal sealed class TaskStackOperation { - data class ReparentTask( - val taskId: Int, - val parentTaskStackId: Int, - val onTop: Boolean - ) : TaskStackOperation() - - data class SendPendingIntent( - val sender: PendingIntent, - val intent: Intent, - val options: Bundle? - ) : TaskStackOperation() - - data class SetTaskStackState( - val taskStackId: Int, - val state: AutoTaskStackState - ) : TaskStackOperation() -} - -data class AutoTaskStackTransaction internal constructor( - internal val operations: MutableList<TaskStackOperation> = mutableListOf() -) { - constructor() : this( - mutableListOf() - ) - - /** See [WindowContainerTransaction.reparent] for more details. */ - fun reparentTask( - taskId: Int, - parentTaskStackId: Int, - onTop: Boolean - ): AutoTaskStackTransaction { - operations.add(TaskStackOperation.ReparentTask(taskId, parentTaskStackId, onTop)) - return this - } - - /** See [WindowContainerTransaction.sendPendingIntent] for more details. */ - fun sendPendingIntent( - sender: PendingIntent, - intent: Intent, - options: Bundle? - ): AutoTaskStackTransaction { - operations.add(TaskStackOperation.SendPendingIntent(sender, intent, options)) - return this - } - - /** - * Adds a set task stack state operation to the transaction. - * - * If an operation with the same task stack ID already exists, it is replaced with the new one. - * - * @param taskStackId The ID of the task stack. - * @param state The new state of the task stack. - * @return The transaction with the added operation. - */ - fun setTaskStackState(taskStackId: Int, state: AutoTaskStackState): AutoTaskStackTransaction { - val existingOperation = operations.find { - it is TaskStackOperation.SetTaskStackState && it.taskStackId == taskStackId - } - if (existingOperation != null) { - val index = operations.indexOf(existingOperation) - operations[index] = TaskStackOperation.SetTaskStackState(taskStackId, state) - } else { - operations.add(TaskStackOperation.SetTaskStackState(taskStackId, state)) - } - return this - } - - /** - * Returns a map of task stack IDs to their states from the set task stack state operations. - * - * @return The map of task stack IDs to states. - */ - fun getTaskStackStates(): Map<Int, AutoTaskStackState> { - val states = mutableMapOf<Int, AutoTaskStackState>() - operations.forEach { operation -> - if (operation is TaskStackOperation.SetTaskStackState) { - states[operation.taskStackId] = operation.state - } - } - return states - } -} - diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStackControllerImpl.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStackControllerImpl.kt deleted file mode 100644 index 8171312762ef..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoTaskStackControllerImpl.kt +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.automotive - -import android.app.ActivityManager -import android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT -import android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS -import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD -import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED -import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW -import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED -import android.os.IBinder -import android.util.Log -import android.util.Slog -import android.view.SurfaceControl -import android.view.SurfaceControl.Transaction -import android.view.WindowManager -import android.view.WindowManager.TRANSIT_CHANGE -import android.window.TransitionInfo -import android.window.TransitionRequestInfo -import android.window.WindowContainerTransaction -import com.android.wm.shell.Flags.enableAutoTaskStackController -import com.android.wm.shell.RootTaskDisplayAreaOrganizer -import com.android.wm.shell.ShellTaskOrganizer -import com.android.wm.shell.common.ShellExecutor -import com.android.wm.shell.dagger.WMSingleton -import com.android.wm.shell.shared.TransitionUtil -import com.android.wm.shell.shared.annotations.ShellMainThread -import com.android.wm.shell.sysui.ShellInit -import com.android.wm.shell.transition.Transitions -import com.android.wm.shell.transition.Transitions.TransitionFinishCallback -import javax.inject.Inject - -const val TAG = "AutoTaskStackController" - -@WMSingleton -class AutoTaskStackControllerImpl @Inject constructor( - val taskOrganizer: ShellTaskOrganizer, - @ShellMainThread private val shellMainThread: ShellExecutor, - val transitions: Transitions, - val shellInit: ShellInit, - val rootTdaOrganizer: RootTaskDisplayAreaOrganizer -) : AutoTaskStackController, Transitions.TransitionHandler { - override var autoTransitionHandlerDelegate: AutoTaskStackTransitionHandlerDelegate? = null - override val taskStackStateMap = mutableMapOf<Int, AutoTaskStackState>() - - private val DBG = Log.isLoggable(TAG, Log.DEBUG) - private val taskStackMap = mutableMapOf<Int, AutoTaskStack>() - private val pendingTransitions = ArrayList<PendingTransition>() - private val mTaskStackStateTranslator = TaskStackStateTranslator() - private val appTasksMap = mutableMapOf<Int, ActivityManager.RunningTaskInfo>() - private val defaultRootTaskPerDisplay = mutableMapOf<Int, Int>() - - init { - if (!enableAutoTaskStackController()) { - throw IllegalStateException("Failed to initialize" + - "AutoTaskStackController as the auto_task_stack_windowing TS flag is disabled.") - } else { - shellInit.addInitCallback(this::onInit, this); - } - } - - fun onInit() { - transitions.addHandler(this) - } - - /** Translates the [AutoTaskStackState] to relevant WM and surface transactions. */ - inner class TaskStackStateTranslator { - // TODO(b/384946072): Move to an interface with 2 implementations, one for root task and - // other for TDA - fun applyVisibilityAndBounds( - wct: WindowContainerTransaction, - taskStack: AutoTaskStack, - state: AutoTaskStackState - ) { - if (taskStack !is RootTaskStack) { - Slog.e(TAG, "Unsupported task stack, unable to convertToWct") - return - } - wct.setBounds(taskStack.rootTaskInfo.token, state.bounds) - wct.reorder(taskStack.rootTaskInfo.token, /* onTop= */ state.childrenTasksVisible) - } - - fun reorderLeash( - taskStack: AutoTaskStack, - state: AutoTaskStackState, - transaction: Transaction - ) { - if (taskStack !is RootTaskStack) { - Slog.e(TAG, "Unsupported task stack, unable to reorder leash") - return - } - Slog.d(TAG, "Setting the layer ${state.layer}") - transaction.setLayer(taskStack.leash, state.layer) - } - - fun restoreLeash(taskStack: AutoTaskStack, transaction: Transaction) { - if (taskStack !is RootTaskStack) { - Slog.e(TAG, "Unsupported task stack, unable to restore leash") - return - } - - val rootTdaInfo = rootTdaOrganizer.getDisplayAreaInfo(taskStack.displayId) - if (rootTdaInfo == null || - rootTdaInfo.featureId != taskStack.rootTaskInfo.displayAreaFeatureId - ) { - Slog.e(TAG, "Cannot find the rootTDA for the root task stack ${taskStack.id}") - return - } - if (DBG) { - Slog.d(TAG, "Reparenting ${taskStack.id} leash to DA ${rootTdaInfo.featureId}") - } - transaction.reparent( - taskStack.leash, - rootTdaOrganizer.getDisplayAreaLeash(taskStack.displayId) - ) - } - } - - inner class RootTaskStackListenerAdapter( - val rootTaskStackListener: RootTaskStackListener, - ) : ShellTaskOrganizer.TaskListener { - private var rootTaskStack: RootTaskStack? = null - - // TODO(b/384948029): Notify car service for all the children tasks' events - override fun onTaskAppeared( - taskInfo: ActivityManager.RunningTaskInfo?, - leash: SurfaceControl? - ) { - if (taskInfo == null) { - throw IllegalArgumentException("taskInfo can't be null in onTaskAppeared") - } - if (leash == null) { - throw IllegalArgumentException("leash can't be null in onTaskAppeared") - } - if (DBG) Slog.d(TAG, "onTaskAppeared = ${taskInfo.taskId}") - - if (rootTaskStack == null) { - val rootTask = - RootTaskStack(taskInfo.taskId, taskInfo.displayId, leash, taskInfo) - taskStackMap[rootTask.id] = rootTask - - rootTaskStack = rootTask; - rootTaskStackListener.onRootTaskStackCreated(rootTask); - return - } - appTasksMap[taskInfo.taskId] = taskInfo - rootTaskStackListener.onTaskAppeared(taskInfo, leash) - } - - override fun onTaskInfoChanged(taskInfo: ActivityManager.RunningTaskInfo?) { - if (taskInfo == null) { - throw IllegalArgumentException("taskInfo can't be null in onTaskInfoChanged") - } - if (DBG) Slog.d(TAG, "onTaskInfoChanged = ${taskInfo.taskId}") - var previousRootTaskStackInfo = rootTaskStack ?: run { - Slog.e(TAG, "Received onTaskInfoChanged, when root task stack is null") - return@onTaskInfoChanged - } - rootTaskStack?.let { - if (taskInfo.taskId == previousRootTaskStackInfo.id) { - previousRootTaskStackInfo = previousRootTaskStackInfo.copy(rootTaskInfo = taskInfo) - taskStackMap[previousRootTaskStackInfo.id] = previousRootTaskStackInfo - rootTaskStack = previousRootTaskStackInfo; - rootTaskStackListener.onRootTaskStackInfoChanged(it) - return - } - } - - appTasksMap[taskInfo.taskId] = taskInfo - rootTaskStackListener.onTaskInfoChanged(taskInfo) - } - - override fun onTaskVanished(taskInfo: ActivityManager.RunningTaskInfo?) { - if (taskInfo == null) { - throw IllegalArgumentException("taskInfo can't be null in onTaskVanished") - } - if (DBG) Slog.d(TAG, "onTaskVanished = ${taskInfo.taskId}") - var rootTask = rootTaskStack ?: run { - Slog.e(TAG, "Received onTaskVanished, when root task stack is null") - return@onTaskVanished - } - if (taskInfo.taskId == rootTask.id) { - rootTask = rootTask.copy(rootTaskInfo = taskInfo) - rootTaskStack = rootTask - rootTaskStackListener.onRootTaskStackDestroyed(rootTask) - taskStackMap.remove(rootTask.id) - taskStackStateMap.remove(rootTask.id) - rootTaskStack = null - return - } - appTasksMap.remove(taskInfo.taskId) - rootTaskStackListener.onTaskVanished(taskInfo) - } - - override fun onBackPressedOnTaskRoot(taskInfo: ActivityManager.RunningTaskInfo?) { - if (taskInfo == null) { - throw IllegalArgumentException("taskInfo can't be null in onBackPressedOnTaskRoot") - } - super.onBackPressedOnTaskRoot(taskInfo) - rootTaskStackListener.onBackPressedOnTaskRoot(taskInfo) - } - } - - override fun createRootTaskStack( - displayId: Int, - listener: RootTaskStackListener - ) { - if (!enableAutoTaskStackController()) { - Slog.e( - TAG, "Failed to create root task stack as the " + - "auto_task_stack_windowing TS flag is disabled." - ) - return - } - taskOrganizer.createRootTask( - displayId, - WINDOWING_MODE_MULTI_WINDOW, - RootTaskStackListenerAdapter(listener), - /* removeWithTaskOrganizer= */ true - ) - } - - override fun setDefaultRootTaskStackOnDisplay(displayId: Int, rootTaskStackId: Int?) { - if (!enableAutoTaskStackController()) { - Slog.e( - TAG, "Failed to set default root task stack as the " + - "auto_task_stack_windowing TS flag is disabled." - ) - return - } - var wct = WindowContainerTransaction() - - // Clear the default root task stack if already set - defaultRootTaskPerDisplay[displayId]?.let { existingDefaultRootTaskStackId -> - (taskStackMap[existingDefaultRootTaskStackId] as? RootTaskStack)?.let { rootTaskStack -> - wct.setLaunchRoot(rootTaskStack.rootTaskInfo.token, null, null) - } - } - - if (rootTaskStackId != null) { - var taskStack = - taskStackMap[rootTaskStackId] ?: run { return@setDefaultRootTaskStackOnDisplay } - if (DBG) Slog.d(TAG, "setting launch root for = ${taskStack.id}") - if (taskStack !is RootTaskStack) { - throw IllegalArgumentException( - "Cannot set a non root task stack as default root task " + - "stack" - ) - } - wct.setLaunchRoot( - taskStack.rootTaskInfo.token, - intArrayOf(WINDOWING_MODE_UNDEFINED), - intArrayOf( - ACTIVITY_TYPE_STANDARD, ACTIVITY_TYPE_UNDEFINED, ACTIVITY_TYPE_RECENTS, - - // TODO(b/386242708): Figure out if this flag will ever be used for automotive - // assistant. Based on output, remove it from here and fix the - // AssistantStackTests accordingly. - ACTIVITY_TYPE_ASSISTANT - ) - ) - } - - taskOrganizer.applyTransaction(wct) - } - - override fun startTransition(transaction: AutoTaskStackTransaction): IBinder? { - if (!enableAutoTaskStackController()) { - Slog.e( - TAG, "Failed to start transaction as the " + - "auto_task_stack_windowing TS flag is disabled." - ) - return null - } - if (transaction.operations.isEmpty()) { - Slog.e(TAG, "Operations empty, no transaction started") - return null - } - if (DBG) Slog.d(TAG, "startTransaction ${transaction.operations}") - - var wct = WindowContainerTransaction() - convertToWct(transaction, wct) - var pending = PendingTransition( - TRANSIT_CHANGE, - wct, - transaction, - ) - return startTransitionNow(pending) - } - - override fun handleRequest( - transition: IBinder, - request: TransitionRequestInfo - ): WindowContainerTransaction? { - if (DBG) { - Slog.d(TAG, "handle request, id=${request.debugId}, type=${request.type}, " + - "triggertask = ${request.triggerTask ?: "null"}") - } - val ast = autoTransitionHandlerDelegate?.handleRequest(transition, request) - ?: run { return@handleRequest null } - - if (ast.operations.isEmpty()) { - return null - } - var wct = WindowContainerTransaction() - convertToWct(ast, wct) - - pendingTransitions.add( - PendingTransition(request.type, wct, ast).apply { isClaimed = transition } - ) - return wct - } - - fun updateTaskStackStates(taskStatStates: Map<Int, AutoTaskStackState>) { - taskStackStateMap.putAll(taskStatStates) - } - - override fun startAnimation( - transition: IBinder, - info: TransitionInfo, - startTransaction: Transaction, - finishTransaction: Transaction, - finishCallback: TransitionFinishCallback - ): Boolean { - if (DBG) Slog.d(TAG, " startAnimation, id=${info.debugId} = changes=" + info.changes) - val pending: PendingTransition? = findPending(transition) - if (pending != null) { - pendingTransitions.remove(pending) - updateTaskStackStates(pending.transaction.getTaskStackStates()) - } - - reorderLeashes(startTransaction) - reorderLeashes(finishTransaction) - - for (chg in info.changes) { - // TODO(b/384946072): handle the da stack similarly. The below implementation only - // handles the root task stack - - val taskInfo = chg.taskInfo ?: continue - val taskStack = taskStackMap[taskInfo.taskId] ?: continue - - // Restore the leashes for the task stacks to ensure correct z-order competition - if (taskStackMap.containsKey(taskInfo.taskId)) { - mTaskStackStateTranslator.restoreLeash( - taskStack, - startTransaction - ) - if (TransitionUtil.isOpeningMode(chg.mode)) { - // Clients can still manipulate the alpha, but this ensures that the default - // behavior is natural - startTransaction.setAlpha(chg.leash, 1f) - } - continue - } - } - - val isPlayedByDelegate = autoTransitionHandlerDelegate?.startAnimation( - transition, - pending?.transaction?.getTaskStackStates() ?: mapOf(), - info, - startTransaction, - finishTransaction, - { - shellMainThread.execute { - finishCallback.onTransitionFinished(it) - startNextTransition() - } - } - ) ?: false - - if (isPlayedByDelegate) { - if (DBG) Slog.d(TAG, "${info.debugId} played"); - return true; - } - - // If for an animation which is not played by the delegate, contains a change in a known - // task stack, it should be leveraged to correct the leashes. So, handle the animation in - // this case. - if (info.changes.any { taskStackMap.containsKey(it.taskInfo?.taskId) }) { - startTransaction.apply() - finishCallback.onTransitionFinished(null) - startNextTransition() - if (DBG) Slog.d(TAG, "${info.debugId} played"); - return true - } - return false; - } - - fun convertToWct(ast: AutoTaskStackTransaction, wct: WindowContainerTransaction) { - ast.operations.forEach { operation -> - when (operation) { - is TaskStackOperation.ReparentTask -> { - val appTask = appTasksMap[operation.taskId] - - if (appTask == null) { - Slog.e( - TAG, "task with id=$operation.taskId not found, failed to " + - "reparent." - ) - return@forEach - } - if (!taskStackMap.containsKey(operation.parentTaskStackId)) { - Slog.e( - TAG, "task stack with id=${operation.parentTaskStackId} not " + - "found, failed to reparent" - ) - return@forEach - } - // TODO(b/384946072): Handle a display area stack as well - wct.reparent( - appTask.token, - (taskStackMap[operation.parentTaskStackId] as RootTaskStack) - .rootTaskInfo.token, - operation.onTop - ) - } - - is TaskStackOperation.SendPendingIntent -> wct.sendPendingIntent( - operation.sender, - operation.intent, - operation.options - ) - - is TaskStackOperation.SetTaskStackState -> { - taskStackMap[operation.taskStackId]?.let { taskStack -> - mTaskStackStateTranslator.applyVisibilityAndBounds( - wct, - taskStack, - operation.state - ) - } - ?: Slog.w(TAG, "AutoTaskStack with id ${operation.taskStackId} " + - "not found.") - } - } - } - } - - override fun mergeAnimation( - transition: IBinder, - info: TransitionInfo, - surfaceTransaction: Transaction, - mergeTarget: IBinder, - finishCallback: TransitionFinishCallback - ) { - val pending: PendingTransition? = findPending(transition) - - autoTransitionHandlerDelegate?.mergeAnimation( - transition, - pending?.transaction?.getTaskStackStates() ?: mapOf(), - info, - surfaceTransaction, - mergeTarget, - /* finishCallback = */ { - shellMainThread.execute { - finishCallback.onTransitionFinished(it) - } - } - ) - } - - override fun onTransitionConsumed( - transition: IBinder, - aborted: Boolean, - finishTransaction: Transaction? - ) { - val pending: PendingTransition? = findPending(transition) - if (pending != null) { - pendingTransitions.remove(pending) - updateTaskStackStates(pending.transaction.getTaskStackStates()) - // Still update the surface order because this means wm didn't lead to any change - if (finishTransaction != null) { - reorderLeashes(finishTransaction) - } - } - autoTransitionHandlerDelegate?.onTransitionConsumed( - transition, - pending?.transaction?.getTaskStackStates() ?: mapOf(), - aborted, - finishTransaction - ) - } - - private fun reorderLeashes(transaction: SurfaceControl.Transaction) { - taskStackStateMap.forEach { (taskId, taskStackState) -> - taskStackMap[taskId]?.let { taskStack -> - mTaskStackStateTranslator.reorderLeash(taskStack, taskStackState, transaction) - } ?: Slog.w(TAG, "Warning: AutoTaskStack with id $taskId not found.") - } - } - - private fun findPending(claimed: IBinder) = pendingTransitions.find { it.isClaimed == claimed } - - private fun startTransitionNow(pending: PendingTransition): IBinder { - val claimedTransition = transitions.startTransition(pending.mType, pending.wct, this) - pending.isClaimed = claimedTransition - pendingTransitions.add(pending) - return claimedTransition - } - - fun startNextTransition() { - if (pendingTransitions.isEmpty()) return - val pending: PendingTransition = pendingTransitions[0] - if (pending.isClaimed != null) { - // Wait for this to start animating. - return - } - pending.isClaimed = transitions.startTransition(pending.mType, pending.wct, this) - } - - internal class PendingTransition( - @field:WindowManager.TransitionType @param:WindowManager.TransitionType val mType: Int, - val wct: WindowContainerTransaction, - val transaction: AutoTaskStackTransaction, - ) { - var isClaimed: IBinder? = null - } - -}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/OWNERS deleted file mode 100644 index 84596b015209..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/OWNERS +++ /dev/null @@ -1,6 +0,0 @@ -# WM shell sub-module automotive owners - -winsonc@google.com -stenning@google.com -gauravbhola@google.com -xiangw@google.com
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/RootTaskStackListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/RootTaskStackListener.kt deleted file mode 100644 index 9d121b144492..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/RootTaskStackListener.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.automotive - -import com.android.wm.shell.ShellTaskOrganizer - -/** - * A [TaskListener] which simplifies the interface when used for - * [ShellTaskOrganizer.createRootTask]. - * - * [onRootTaskStackCreated], [onRootTaskStackInfoChanged], [onRootTaskStackDestroyed] will be called - * for the underlying root task. - * The [onTaskAppeared], [onTaskInfoChanged], [onTaskVanished] are called for the children tasks. - */ -interface RootTaskStackListener : ShellTaskOrganizer.TaskListener { - fun onRootTaskStackCreated(rootTaskStack: RootTaskStack) - fun onRootTaskStackInfoChanged(rootTaskStack: RootTaskStack) - fun onRootTaskStackDestroyed(rootTaskStack: RootTaskStack) -}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 4e7f87c48a86..f1f49eda75b6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -633,8 +633,6 @@ public class BubbleStackView extends FrameLayout mMagneticTarget, mIndividualBubbleMagnetListener); - hideCurrentInputMethod(); - // Save the magnetized individual bubble so we can dispatch touch events to it. mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut(); } else { @@ -671,6 +669,10 @@ public class BubbleStackView extends FrameLayout return; } + if (mPositioner.isImeVisible()) { + hideCurrentInputMethod(); + } + // Show the dismiss target, if we haven't already. mDismissView.show(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/UserProfileContexts.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/UserProfileContexts.kt new file mode 100644 index 000000000000..0577f9e625ca --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/UserProfileContexts.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.common + +import android.app.ActivityManager +import android.content.Context +import android.content.pm.UserInfo +import android.os.UserHandle +import android.os.UserManager +import android.util.SparseArray +import com.android.wm.shell.sysui.ShellController +import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.sysui.UserChangeListener + +/** Creates and manages contexts for all the profiles of the current user. */ +class UserProfileContexts( + private val baseContext: Context, + private val shellController: ShellController, + shellInit: ShellInit, +) { + // Contexts for all the profiles of the current user. + private val currentProfilesContext = SparseArray<Context>() + + lateinit var userContext: Context + private set + + init { + shellInit.addInitCallback(this::onInit, this) + } + + private fun onInit() { + shellController.addUserChangeListener( + object : UserChangeListener { + override fun onUserChanged(newUserId: Int, userContext: Context) { + currentProfilesContext.clear() + this@UserProfileContexts.userContext = userContext + currentProfilesContext.put(newUserId, userContext) + } + + override fun onUserProfilesChanged(profiles: List<UserInfo>) { + updateProfilesContexts(profiles) + } + } + ) + val defaultUserId = ActivityManager.getCurrentUser() + val userManager = baseContext.getSystemService(UserManager::class.java) + userContext = baseContext.createContextAsUser(UserHandle.of(defaultUserId), /* flags= */ 0) + updateProfilesContexts(userManager.getProfiles(defaultUserId)) + } + + private fun updateProfilesContexts(profiles: List<UserInfo>) { + for (profile in profiles) { + if (profile.id in currentProfilesContext) continue + val profileContext = baseContext.createContextAsUser(profile.userHandle, /* flags= */ 0) + currentProfilesContext.put(profile.id, profileContext) + } + val profilesToRemove = buildList<Int> { + for (i in 0..<currentProfilesContext.size()) { + val userId = currentProfilesContext.keyAt(i) + if (profiles.none { it.id == userId }) { + add(userId) + } + } + } + profilesToRemove.forEach { currentProfilesContext.remove(it) } + } + + operator fun get(userId: Int): Context? = currentProfilesContext.get(userId) +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl index 37779077f9b6..1444a626fb11 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/IPip.aidl @@ -16,7 +16,7 @@ package com.android.wm.shell.common.pip; -import android.app.ActivityManager; +import android.app.ActivityManager.RunningTaskInfo; import android.app.PictureInPictureParams; import android.view.SurfaceControl; import android.content.ComponentName; @@ -42,7 +42,7 @@ interface IPip { bounds * @return destination bounds the PiP window should land into */ - Rect startSwipePipToHome(in ActivityManager.RunningTaskInfo taskInfo, int launcherRotation, + Rect startSwipePipToHome(in RunningTaskInfo taskInfo, int launcherRotation, in Rect hotseatKeepClearArea) = 1; /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java index 83e5e31bd125..84c30a52e8a6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java @@ -76,8 +76,7 @@ public class SplitScreenUtils { * Returns whether left/right split is allowed in portrait. */ public static boolean allowLeftRightSplitInPortrait(Resources res) { - return Flags.enableLeftRightSplitInPortrait() && res.getBoolean( - com.android.internal.R.bool.config_leftRightSplitInPortrait); + return res.getBoolean(com.android.internal.R.bool.config_leftRightSplitInPortrait); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 67e345365d26..1bdb5922a102 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -70,6 +70,7 @@ import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TaskStackListenerImpl; +import com.android.wm.shell.common.UserProfileContexts; import com.android.wm.shell.common.split.SplitState; import com.android.wm.shell.compatui.letterbox.LetterboxCommandHandler; import com.android.wm.shell.compatui.letterbox.LetterboxTransitionObserver; @@ -95,6 +96,7 @@ import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler; +import com.android.wm.shell.desktopmode.OverviewToDesktopTransitionObserver; import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator; import com.android.wm.shell.desktopmode.SpringDragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler; @@ -107,6 +109,8 @@ import com.android.wm.shell.desktopmode.education.AppToWebEducationController; import com.android.wm.shell.desktopmode.education.AppToWebEducationFilter; import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatastoreRepository; import com.android.wm.shell.desktopmode.education.data.AppToWebEducationDatastoreRepository; +import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer; +import com.android.wm.shell.desktopmode.multidesks.RootTaskDesksOrganizer; import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository; import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer; import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializerImpl; @@ -394,6 +398,7 @@ public abstract class WMShellModule { ShellTaskOrganizer shellTaskOrganizer, Optional<DesktopUserRepositories> desktopUserRepositories, Optional<DesktopTasksController> desktopTasksController, + DesktopModeLoggerTransitionObserver desktopModeLoggerTransitionObserver, LaunchAdjacentController launchAdjacentController, WindowDecorViewModel windowDecorViewModel, Optional<TaskChangeListener> taskChangeListener) { @@ -406,6 +411,7 @@ public abstract class WMShellModule { shellTaskOrganizer, desktopUserRepositories, desktopTasksController, + desktopModeLoggerTransitionObserver, launchAdjacentController, windowDecorViewModel, taskChangeListener); @@ -702,6 +708,16 @@ public abstract class WMShellModule { @WMSingleton @Provides + static DesksOrganizer provideDesksOrganizer( + @NonNull ShellInit shellInit, + @NonNull ShellCommandHandler shellCommandHandler, + @NonNull ShellTaskOrganizer shellTaskOrganizer + ) { + return new RootTaskDesksOrganizer(shellInit, shellCommandHandler, shellTaskOrganizer); + } + + @WMSingleton + @Provides @DynamicOverride static DesktopTasksController provideDesktopTasksController( Context context, @@ -739,7 +755,10 @@ public abstract class WMShellModule { DesktopModeUiEventLogger desktopModeUiEventLogger, DesktopTilingDecorViewModel desktopTilingDecorViewModel, DesktopWallpaperActivityTokenProvider desktopWallpaperActivityTokenProvider, - Optional<BubbleController> bubbleController) { + Optional<BubbleController> bubbleController, + OverviewToDesktopTransitionObserver overviewToDesktopTransitionObserver, + DesksOrganizer desksOrganizer, + UserProfileContexts userProfileContexts) { return new DesktopTasksController( context, shellInit, @@ -772,7 +791,10 @@ public abstract class WMShellModule { desktopModeUiEventLogger, desktopTilingDecorViewModel, desktopWallpaperActivityTokenProvider, - bubbleController); + bubbleController, + overviewToDesktopTransitionObserver, + desksOrganizer, + userProfileContexts); } @WMSingleton @@ -974,9 +996,10 @@ public abstract class WMShellModule { static WindowDecorTaskResourceLoader provideWindowDecorTaskResourceLoader( @NonNull Context context, @NonNull ShellInit shellInit, @NonNull ShellController shellController, - @NonNull ShellCommandHandler shellCommandHandler) { + @NonNull ShellCommandHandler shellCommandHandler, + @NonNull UserProfileContexts userProfileContexts) { return new WindowDecorTaskResourceLoader(context, shellInit, shellController, - shellCommandHandler); + shellCommandHandler, userProfileContexts); } @WMSingleton @@ -1180,10 +1203,11 @@ public abstract class WMShellModule { Transitions transitions, DisplayController displayController, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, - IWindowManager windowManager + IWindowManager windowManager, + Optional<DesktopUserRepositories> desktopUserRepositories, + Optional<DesktopTasksController> desktopTasksController ) { - if (!DesktopModeStatus.canEnterDesktopMode(context) - || !Flags.enableDisplayWindowingModeSwitching()) { + if (!DesktopModeStatus.canEnterDesktopMode(context)) { return Optional.empty(); } return Optional.of( @@ -1193,7 +1217,9 @@ public abstract class WMShellModule { transitions, displayController, rootTaskDisplayAreaOrganizer, - windowManager)); + windowManager, + desktopUserRepositories.get(), + desktopTasksController.get())); } @WMSingleton @@ -1397,4 +1423,20 @@ public abstract class WMShellModule { return new Object(); } + @WMSingleton + @Provides + static OverviewToDesktopTransitionObserver provideOverviewToDesktopTransitionObserver( + Transitions transitions, ShellInit shellInit) { + return new OverviewToDesktopTransitionObserver(transitions, shellInit); + } + + @WMSingleton + @Provides + static UserProfileContexts provideUserProfilesContexts( + Context context, + ShellController shellController, + ShellInit shellInit) { + return new UserProfileContexts(context, shellController, shellInit); + } + } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt index 43e8d2a30930..760d2124b845 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt @@ -24,9 +24,14 @@ import android.view.Display.DEFAULT_DISPLAY import android.view.IWindowManager import android.view.WindowManager.TRANSIT_CHANGE import android.window.WindowContainerTransaction +import com.android.internal.protolog.ProtoLog +import com.android.window.flags.Flags import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener +import com.android.wm.shell.desktopmode.multidesks.OnDeskRemovedListener +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE +import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions @@ -38,7 +43,12 @@ class DesktopDisplayEventHandler( private val displayController: DisplayController, private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, private val windowManager: IWindowManager, -) : OnDisplaysChangedListener { + private val desktopUserRepositories: DesktopUserRepositories, + private val desktopTasksController: DesktopTasksController, +) : OnDisplaysChangedListener, OnDeskRemovedListener { + + private val desktopRepository: DesktopRepository + get() = desktopUserRepositories.current init { shellInit.addInitCallback({ onInit() }, this) @@ -46,23 +56,43 @@ class DesktopDisplayEventHandler( private fun onInit() { displayController.addDisplayWindowListener(this) + + if (Flags.enableMultipleDesktopsBackend()) { + desktopTasksController.onDeskRemovedListener = this + } } override fun onDisplayAdded(displayId: Int) { - if (displayId == DEFAULT_DISPLAY) { + if (displayId != DEFAULT_DISPLAY) { + refreshDisplayWindowingMode() + } + + if (!supportsDesks(displayId)) { + logV("Display #$displayId does not support desks") return } - refreshDisplayWindowingMode() + logV("Creating new desk in new display#$displayId") + desktopTasksController.createDesk(displayId) } override fun onDisplayRemoved(displayId: Int) { - if (displayId == DEFAULT_DISPLAY) { - return + if (displayId != DEFAULT_DISPLAY) { + refreshDisplayWindowingMode() + } + + // TODO: b/362720497 - move desks in closing display to the remaining desk. + } + + override fun onDeskRemoved(lastDisplayId: Int, deskId: Int) { + val remainingDesks = desktopRepository.getNumberOfDesks(lastDisplayId) + if (remainingDesks == 0) { + logV("All desks removed from display#$lastDisplayId, creating empty desk") + desktopTasksController.createDesk(lastDisplayId) } - refreshDisplayWindowingMode() } private fun refreshDisplayWindowingMode() { + if (!Flags.enableDisplayWindowingModeSwitching()) return // TODO: b/375319538 - Replace the check with a DisplayManager API once it's available. val isExtendedDisplayEnabled = 0 != @@ -98,4 +128,16 @@ class DesktopDisplayEventHandler( wct.setWindowingMode(tdaInfo.token, targetDisplayWindowingMode) transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) } + + // TODO: b/362720497 - connected/projected display considerations. + private fun supportsDesks(displayId: Int): Boolean = + DesktopModeStatus.canEnterDesktopMode(context) + + private fun logV(msg: String, vararg arguments: Any?) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + companion object { + private const val TAG = "DesktopDisplayEventHandler" + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt index a43358603bc3..3b051694ae81 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt @@ -167,6 +167,29 @@ class DesktopModeLoggerTransitionObserver( override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {} + fun onTaskVanished(taskInfo: RunningTaskInfo) { + // At this point the task should have been cleared up due to transition. If it's not yet + // cleared up, it might be one of the edge cases where transitions don't give the correct + // signal. + if (visibleFreeformTaskInfos.containsKey(taskInfo.taskId)) { + val postTransitionFreeformTasks: SparseArray<TaskInfo> = SparseArray() + postTransitionFreeformTasks.putAll(visibleFreeformTaskInfos) + postTransitionFreeformTasks.remove(taskInfo.taskId) + ProtoLog.v( + WM_SHELL_DESKTOP_MODE, + "DesktopModeLogger: processing tasks after task vanished %s", + postTransitionFreeformTasks.size(), + ) + identifyLogEventAndUpdateState( + transition = null, + transitionInfo = null, + preTransitionVisibleFreeformTasks = visibleFreeformTaskInfos, + postTransitionVisibleFreeformTasks = postTransitionFreeformTasks, + newFocusedFreeformTask = null, + ) + } + } + // Returns null if there was no change in focused task private fun getNewFocusedFreeformTask(info: TransitionInfo): TaskInfo? { val freeformWindowChanges = @@ -253,8 +276,8 @@ class DesktopModeLoggerTransitionObserver( * state and update it */ private fun identifyLogEventAndUpdateState( - transition: IBinder, - transitionInfo: TransitionInfo, + transition: IBinder?, + transitionInfo: TransitionInfo?, preTransitionVisibleFreeformTasks: SparseArray<TaskInfo>, postTransitionVisibleFreeformTasks: SparseArray<TaskInfo>, newFocusedFreeformTask: TaskInfo?, @@ -310,8 +333,8 @@ class DesktopModeLoggerTransitionObserver( /** Compare the old and new state of taskInfos and identify and log the changes */ private fun identifyAndLogTaskUpdates( - transition: IBinder, - transitionInfo: TransitionInfo, + transition: IBinder?, + transitionInfo: TransitionInfo?, preTransitionVisibleFreeformTasks: SparseArray<TaskInfo>, postTransitionVisibleFreeformTasks: SparseArray<TaskInfo>, newFocusedFreeformTask: TaskInfo?, @@ -384,22 +407,24 @@ class DesktopModeLoggerTransitionObserver( } private fun getMinimizeReason( - transition: IBinder, - transitionInfo: TransitionInfo, + transition: IBinder?, + transitionInfo: TransitionInfo?, taskInfo: TaskInfo, ): MinimizeReason? { - if (transitionInfo.type == Transitions.TRANSIT_MINIMIZE) { + if (transitionInfo?.type == Transitions.TRANSIT_MINIMIZE) { return MinimizeReason.MINIMIZE_BUTTON } - val minimizingTask = desktopTasksLimiter.getOrNull()?.getMinimizingTask(transition) + val minimizingTask = + transition?.let { desktopTasksLimiter.getOrNull()?.getMinimizingTask(transition) } if (minimizingTask?.taskId == taskInfo.taskId) { return minimizingTask.minimizeReason } return null } - private fun getUnminimizeReason(transition: IBinder, taskInfo: TaskInfo): UnminimizeReason? { - val unminimizingTask = desktopTasksLimiter.getOrNull()?.getUnminimizingTask(transition) + private fun getUnminimizeReason(transition: IBinder?, taskInfo: TaskInfo): UnminimizeReason? { + val unminimizingTask = + transition?.let { desktopTasksLimiter.getOrNull()?.getUnminimizingTask(transition) } if (unminimizingTask?.taskId == taskInfo.taskId) { return unminimizingTask.unminimizeReason } @@ -441,24 +466,24 @@ class DesktopModeLoggerTransitionObserver( } /** Get [EnterReason] for this session enter */ - private fun getEnterReason(transitionInfo: TransitionInfo): EnterReason { + private fun getEnterReason(transitionInfo: TransitionInfo?): EnterReason { val enterReason = when { - transitionInfo.type == WindowManager.TRANSIT_WAKE + transitionInfo?.type == WindowManager.TRANSIT_WAKE // If there is a screen lock, desktop window entry is after dismissing keyguard || - (transitionInfo.type == WindowManager.TRANSIT_TO_BACK && + (transitionInfo?.type == WindowManager.TRANSIT_TO_BACK && wasPreviousTransitionExitByScreenOff) -> EnterReason.SCREEN_ON - transitionInfo.type == TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP -> + transitionInfo?.type == TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP -> EnterReason.APP_HANDLE_DRAG - transitionInfo.type == TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON -> + transitionInfo?.type == TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON -> EnterReason.APP_HANDLE_MENU_BUTTON - transitionInfo.type == TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW -> + transitionInfo?.type == TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW -> EnterReason.APP_FROM_OVERVIEW - transitionInfo.type == TRANSIT_ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT -> + transitionInfo?.type == TRANSIT_ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT -> EnterReason.KEYBOARD_SHORTCUT_ENTER // NOTE: the below condition also applies for EnterReason quickswitch - transitionInfo.type == WindowManager.TRANSIT_TO_FRONT -> EnterReason.OVERVIEW + transitionInfo?.type == WindowManager.TRANSIT_TO_FRONT -> EnterReason.OVERVIEW // Enter desktop mode from cancelled recents has no transition. Enter is detected on // the // next transition involving freeform windows. @@ -469,12 +494,13 @@ class DesktopModeLoggerTransitionObserver( // after // a cancelled recents. wasPreviousTransitionExitToOverview -> EnterReason.OVERVIEW - transitionInfo.type == WindowManager.TRANSIT_OPEN -> EnterReason.APP_FREEFORM_INTENT + transitionInfo?.type == WindowManager.TRANSIT_OPEN -> + EnterReason.APP_FREEFORM_INTENT else -> { ProtoLog.w( WM_SHELL_DESKTOP_MODE, "Unknown enter reason for transition type: %s", - transitionInfo.type, + transitionInfo?.type, ) EnterReason.UNKNOWN_ENTER } @@ -484,30 +510,31 @@ class DesktopModeLoggerTransitionObserver( } /** Get [ExitReason] for this session exit */ - private fun getExitReason(transitionInfo: TransitionInfo): ExitReason = + private fun getExitReason(transitionInfo: TransitionInfo?): ExitReason = when { - transitionInfo.type == WindowManager.TRANSIT_SLEEP -> { + transitionInfo?.type == WindowManager.TRANSIT_SLEEP -> { wasPreviousTransitionExitByScreenOff = true ExitReason.SCREEN_OFF } // TODO(b/384490301): differentiate back gesture / button exit from clicking the close // button located in the window top corner. - transitionInfo.type == WindowManager.TRANSIT_TO_BACK -> ExitReason.TASK_MOVED_TO_BACK - transitionInfo.type == WindowManager.TRANSIT_CLOSE -> ExitReason.TASK_FINISHED - transitionInfo.type == TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG -> ExitReason.DRAG_TO_EXIT - transitionInfo.type == TRANSIT_EXIT_DESKTOP_MODE_HANDLE_MENU_BUTTON -> + transitionInfo?.type == WindowManager.TRANSIT_TO_BACK -> ExitReason.TASK_MOVED_TO_BACK + transitionInfo?.type == WindowManager.TRANSIT_CLOSE -> ExitReason.TASK_FINISHED + transitionInfo?.type == TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG -> ExitReason.DRAG_TO_EXIT + transitionInfo?.type == TRANSIT_EXIT_DESKTOP_MODE_HANDLE_MENU_BUTTON -> ExitReason.APP_HANDLE_MENU_BUTTON_EXIT - transitionInfo.type == TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT -> + transitionInfo?.type == TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT -> ExitReason.KEYBOARD_SHORTCUT_EXIT - transitionInfo.isExitToRecentsTransition() -> ExitReason.RETURN_HOME_OR_OVERVIEW - transitionInfo.type == Transitions.TRANSIT_MINIMIZE -> ExitReason.TASK_MINIMIZED + transitionInfo?.isExitToRecentsTransition() == true -> + ExitReason.RETURN_HOME_OR_OVERVIEW + transitionInfo?.type == Transitions.TRANSIT_MINIMIZE -> ExitReason.TASK_MINIMIZED else -> { ProtoLog.w( WM_SHELL_DESKTOP_MODE, "Unknown exit reason for transition type: %s", - transitionInfo.type, + transitionInfo?.type, ) ExitReason.UNKNOWN_EXIT } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt index 9b9988457808..164d04bbde65 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt @@ -110,8 +110,8 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl pw.println("Error: display id should be an integer") return false } - pw.println("Not implemented.") - return false + controller.createDesk(displayId) + return true } private fun runActivateDesk(args: Array<String>, pw: PrintWriter): Boolean { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt index fa696682de28..6636770895fa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt @@ -171,6 +171,9 @@ class DesktopRepository( /** Returns a list of all [Desk]s in the repository. */ private fun desksSequence(): Sequence<Desk> = desktopData.desksSequence() + /** Returns the number of desks in the given display. */ + fun getNumberOfDesks(displayId: Int) = desktopData.getNumberOfDesks(displayId) + /** Adds [regionListener] to inform about changes to exclusion regions for all Desktop tasks. */ fun setExclusionRegionListener(regionListener: Consumer<Region>, executor: Executor) { desktopGestureExclusionListener = regionListener @@ -201,11 +204,11 @@ class DesktopRepository( /** Adds the given desk under the given display. */ fun addDesk(displayId: Int, deskId: Int) { - desktopData.getOrCreateDesk(displayId, deskId) + desktopData.createDesk(displayId, deskId) } /** Returns the default desk in the given display. */ - fun getDefaultDesk(displayId: Int): Int? = desktopData.getDefaultDesk(displayId)?.deskId + private fun getDefaultDesk(displayId: Int): Desk? = desktopData.getDefaultDesk(displayId) /** Sets the given desk as the active one in the given display. */ fun setActiveDesk(displayId: Int, deskId: Int) { @@ -229,15 +232,14 @@ class DesktopRepository( * TODO: b/389960283 - add explicit [deskId] argument. */ private fun addActiveTask(displayId: Int, taskId: Int) { - val activeDeskId = - desktopData.getActiveDesk(displayId)?.deskId - ?: error("Expected active desk in display: $displayId") + val activeDesk = desktopData.getDefaultDesk(displayId) + checkNotNull(activeDesk) { "Expected desk in display: $displayId" } // Removes task if it is active on another desk excluding [activeDesk]. - removeActiveTask(taskId, excludedDeskId = activeDeskId) + removeActiveTask(taskId, excludedDeskId = activeDesk.deskId) - if (desktopData.getOrCreateDesk(displayId, activeDeskId).activeTasks.add(taskId)) { - logD("Adds active task=%d displayId=%d deskId=%d", taskId, displayId, activeDeskId) + if (activeDesk.activeTasks.add(taskId)) { + logD("Adds active task=%d displayId=%d deskId=%d", taskId, displayId, activeDesk.deskId) updateActiveTasksListeners(displayId) } } @@ -266,18 +268,23 @@ class DesktopRepository( * TODO: b/389960283 - add explicit [deskId] argument. */ fun addClosingTask(displayId: Int, taskId: Int) { - val activeDeskId = - desktopData.getActiveDesk(displayId)?.deskId + val activeDesk = + desktopData.getActiveDesk(displayId) ?: error("Expected active desk in display: $displayId") - if (desktopData.getOrCreateDesk(displayId, activeDeskId).closingTasks.add(taskId)) { - logD("Added closing task=%d displayId=%d deskId=%d", taskId, displayId, activeDeskId) + if (activeDesk.closingTasks.add(taskId)) { + logD( + "Added closing task=%d displayId=%d deskId=%d", + taskId, + displayId, + activeDesk.deskId, + ) } else { // If the task hasn't been removed from closing list after it disappeared. logW( "Task with taskId=%d displayId=%d deskId=%d is already closing", taskId, displayId, - activeDeskId, + activeDesk.deskId, ) } } @@ -323,7 +330,7 @@ class DesktopRepository( /** * Returns the active tasks in the given display's active desk. * - * TODO: b/389960283 - add explicit [deskId] argument. + * TODO: b/389960283 - migrate callers to [getActiveTaskIdsInDesk]. */ @VisibleForTesting fun getActiveTasks(displayId: Int): ArraySet<Int> = @@ -332,19 +339,27 @@ class DesktopRepository( /** * Returns the minimized tasks in the given display's active desk. * - * TODO: b/389960283 - add explicit [deskId] argument. + * TODO: b/389960283 - migrate callers to [getMinimizedTaskIdsInDesk]. */ fun getMinimizedTasks(displayId: Int): ArraySet<Int> = ArraySet(desktopData.getActiveDesk(displayId)?.minimizedTasks) + @VisibleForTesting + fun getMinimizedTaskIdsInDesk(deskId: Int): ArraySet<Int> = + ArraySet(desktopData.getDesk(deskId)?.minimizedTasks) + /** * Returns all active non-minimized tasks for [displayId] ordered from top to bottom. * - * TODO: b/389960283 - add explicit [deskId] argument. + * TODO: b/389960283 - migrate callers to [getExpandedTasksIdsInDeskOrdered]. */ fun getExpandedTasksOrdered(displayId: Int): List<Int> = getFreeformTasksInZOrder(displayId).filter { !isMinimizedTask(it) } + @VisibleForTesting + fun getExpandedTasksIdsInDeskOrdered(deskId: Int): List<Int> = + getFreeformTasksIdsInDeskInZOrder(deskId).filter { !isMinimizedTask(it) } + /** * Returns the count of active non-minimized tasks for [displayId]. * @@ -357,11 +372,15 @@ class DesktopRepository( /** * Returns a list of freeform tasks, ordered from top-bottom (top at index 0). * - * TODO: b/389960283 - add explicit [deskId] argument. + * TODO: b/389960283 - migrate callers to [getFreeformTasksIdsInDeskInZOrder]. */ @VisibleForTesting fun getFreeformTasksInZOrder(displayId: Int): ArrayList<Int> = - ArrayList(desktopData.getActiveDesk(displayId)?.freeformTasksInZOrder ?: emptyList()) + ArrayList(desktopData.getDefaultDesk(displayId)?.freeformTasksInZOrder ?: emptyList()) + + @VisibleForTesting + fun getFreeformTasksIdsInDeskInZOrder(deskId: Int): ArrayList<Int> = + ArrayList(desktopData.getDesk(deskId)?.freeformTasksInZOrder ?: emptyList()) /** Returns the tasks inside the given desk. */ fun getActiveTaskIdsInDesk(deskId: Int): Set<Int> = @@ -401,8 +420,8 @@ class DesktopRepository( } val prevCount = getVisibleTaskCount(displayId) if (isVisible) { - desktopData.getActiveDesk(displayId)?.visibleTasks?.add(taskId) - ?: error("Expected non-null active desk in display $displayId") + desktopData.getDefaultDesk(displayId)?.visibleTasks?.add(taskId) + ?: error("Expected non-null desk in display $displayId") unminimizeTask(displayId, taskId) } else { desktopData.getActiveDesk(displayId)?.visibleTasks?.remove(taskId) @@ -587,17 +606,15 @@ class DesktopRepository( * TODO: b/389960283 - add explicit [deskId] argument. */ private fun addOrMoveFreeformTaskToTop(displayId: Int, taskId: Int) { - val activeDesk = - desktopData.getActiveDesk(displayId) - ?: error("Expected a desk to be active in display: $displayId") + val desk = getDefaultDesk(displayId) ?: error("Expected a desk in display: $displayId") logD( "Add or move task to top: display=%d taskId=%d deskId=%d", taskId, displayId, - activeDesk.deskId, + desk.deskId, ) - desktopData.forAllDesks { _, desk -> desk.freeformTasksInZOrder.remove(taskId) } - activeDesk.freeformTasksInZOrder.add(0, taskId) + desktopData.forAllDesks { _, desk1 -> desk1.freeformTasksInZOrder.remove(taskId) } + desk.freeformTasksInZOrder.add(0, taskId) // Unminimize the task if it is minimized. unminimizeTask(displayId, taskId) if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) { @@ -835,13 +852,8 @@ class DesktopRepository( /** An interface for the desktop hierarchy's data managed by this repository. */ private interface DesktopData { - /** - * Returns the existing desk or creates a new entry if needed. - * - * TODO: 389787966 - consider removing this as it cannot be assumed a desk can be created in - * all devices / form-factors. - */ - fun getOrCreateDesk(displayId: Int, deskId: Int): Desk + /** Creates a desk record. */ + fun createDesk(displayId: Int, deskId: Int) /** Returns the desk with the given id, or null if it does not exist. */ fun getDesk(deskId: Int): Desk? @@ -894,7 +906,8 @@ class DesktopRepository( /** * A [DesktopData] implementation that only supports one desk per display. * - * Internally, it reuses the displayId as that display's single desk's id. + * Internally, it reuses the displayId as that display's single desk's id. It also never truly + * "removes" a desk, it just clears its content. */ private class SingleDesktopData : DesktopData { private val deskByDisplayId = @@ -907,12 +920,13 @@ class DesktopRepository( } } - override fun getOrCreateDesk(displayId: Int, deskId: Int): Desk { - check(displayId == deskId) - return deskByDisplayId.getOrCreate(displayId) + override fun createDesk(displayId: Int, deskId: Int) { + check(displayId == deskId) { "Display and desk ids must match" } + deskByDisplayId.getOrCreate(displayId) } - override fun getDesk(deskId: Int): Desk = getOrCreateDesk(deskId, deskId) + override fun getDesk(deskId: Int): Desk = + checkNotNull(deskByDisplayId[deskId]) { "Expected desk $deskId to exist" } override fun getActiveDesk(displayId: Int): Desk { // TODO: 389787966 - consider migrating to an "active" state instead of checking the @@ -927,7 +941,7 @@ class DesktopRepository( // existence of visible desktop windows, among other factors. } - override fun getDefaultDesk(displayId: Int): Desk = getOrCreateDesk(displayId, displayId) + override fun getDefaultDesk(displayId: Int): Desk = getDesk(deskId = displayId) override fun getAllActiveDesks(): Set<Desk> = deskByDisplayId.valueIterator().asSequence().toSet() @@ -943,7 +957,7 @@ class DesktopRepository( } override fun forAllDesks(displayId: Int, consumer: (Desk) -> Unit) { - consumer(getOrCreateDesk(displayId, displayId)) + consumer(getDesk(deskId = displayId)) } override fun desksSequence(): Sequence<Desk> = deskByDisplayId.valueIterator().asSequence() @@ -962,16 +976,14 @@ class DesktopRepository( private class MultiDesktopData : DesktopData { private val desktopDisplays = SparseArray<DesktopDisplay>() - override fun getOrCreateDesk(displayId: Int, deskId: Int): Desk { + override fun createDesk(displayId: Int, deskId: Int) { val display = desktopDisplays[displayId] ?: DesktopDisplay(displayId).also { desktopDisplays[displayId] = it } - val desk = - display.orderedDesks.find { desk -> desk.deskId == deskId } - ?: Desk(deskId = deskId, displayId = displayId).also { - display.orderedDesks.add(it) - } - return desk + check(display.orderedDesks.none { desk -> desk.deskId == deskId }) { + "Attempting to create desk#$deskId that already exists in display#$displayId" + } + display.orderedDesks.add(Desk(deskId = deskId, displayId = displayId)) } override fun getDesk(deskId: Int): Desk? { @@ -999,7 +1011,8 @@ class DesktopRepository( override fun getDefaultDesk(displayId: Int): Desk? { val display = desktopDisplays[displayId] ?: return null - return display.orderedDesks.firstOrNull() + return display.orderedDesks.find { it.deskId == display.activeDeskId } + ?: display.orderedDesks.firstOrNull() } override fun getAllActiveDesks(): Set<Desk> { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt index c958a0975f11..4d87b2189115 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt @@ -70,8 +70,7 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser if (!isFreeformTask(taskInfo)) { desktopRepository.removeTask(taskInfo.displayId, taskInfo.taskId) } - // TODO: b/367268953 - Connect this with DesktopRepository for handling - // task moving to front for tasks in windowing mode. + desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible) } override fun onTaskMovingToBack(taskInfo: RunningTaskInfo) { 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 2b4b27046ac3..f0a12e05a400 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 @@ -85,6 +85,7 @@ import com.android.wm.shell.common.RemoteCallable import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.SingleInstanceRemoteListener import com.android.wm.shell.common.SyncTransactionQueue +import com.android.wm.shell.common.UserProfileContexts import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing import com.android.wm.shell.compatui.isTransparentTask import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod @@ -102,6 +103,8 @@ import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCR import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider import com.android.wm.shell.desktopmode.minimize.DesktopWindowLimitRemoteHandler +import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer +import com.android.wm.shell.desktopmode.multidesks.OnDeskRemovedListener import com.android.wm.shell.draganddrop.DragAndDropController import com.android.wm.shell.freeform.FreeformTaskTransitionStarter import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE @@ -179,6 +182,9 @@ class DesktopTasksController( private val desktopTilingDecorViewModel: DesktopTilingDecorViewModel, private val desktopWallpaperActivityTokenProvider: DesktopWallpaperActivityTokenProvider, private val bubbleController: Optional<BubbleController>, + private val overviewToDesktopTransitionObserver: OverviewToDesktopTransitionObserver, + private val desksOrganizer: DesksOrganizer, + private val userProfileContexts: UserProfileContexts, ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, @@ -231,6 +237,9 @@ class DesktopTasksController( // Used to prevent handleRequest from moving the new fullscreen task to freeform. private var dragAndDropFullscreenCookie: Binder? = null + // A listener that is invoked after a desk has been remove from the system. */ + var onDeskRemovedListener: OnDeskRemovedListener? = null + init { desktopMode = DesktopModeImpl() if (DesktopModeStatus.canEnterDesktopMode(context)) { @@ -414,18 +423,38 @@ class DesktopTasksController( return isFreeformDisplay } + /** Creates a new desk in the given display. */ + fun createDesk(displayId: Int) { + if (Flags.enableMultipleDesktopsBackend()) { + desksOrganizer.createDesk(displayId) { deskId -> + taskRepository.addDesk(displayId = displayId, deskId = deskId) + } + } else { + // In single-desk, the desk reuses the display id. + taskRepository.addDesk(displayId = displayId, deskId = displayId) + } + } + /** Moves task to desktop mode if task is running, else launches it in desktop mode. */ + @JvmOverloads fun moveTaskToDesktop( taskId: Int, wct: WindowContainerTransaction = WindowContainerTransaction(), transitionSource: DesktopModeTransitionSource, remoteTransition: RemoteTransition? = null, + callback: IMoveToDesktopCallback? = null, ): Boolean { val runningTask = shellTaskOrganizer.getRunningTaskInfo(taskId) if (runningTask == null) { - return moveBackgroundTaskToDesktop(taskId, wct, transitionSource, remoteTransition) + return moveBackgroundTaskToDesktop( + taskId, + wct, + transitionSource, + remoteTransition, + callback, + ) } - moveRunningTaskToDesktop(runningTask, wct, transitionSource, remoteTransition) + moveRunningTaskToDesktop(runningTask, wct, transitionSource, remoteTransition, callback) return true } @@ -434,6 +463,7 @@ class DesktopTasksController( wct: WindowContainerTransaction, transitionSource: DesktopModeTransitionSource, remoteTransition: RemoteTransition? = null, + callback: IMoveToDesktopCallback? = null, ): Boolean { if (recentTasksController?.findTaskInBackground(taskId) == null) { logW("moveBackgroundTaskToDesktop taskId=%d not found", taskId) @@ -466,6 +496,7 @@ class DesktopTasksController( } else { // TODO(343149901): Add DPI changes for task launch transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource) + invokeCallbackToOverview(transition, callback) } desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted( FREEFORM_ANIMATION_DURATION @@ -483,6 +514,7 @@ class DesktopTasksController( wct: WindowContainerTransaction = WindowContainerTransaction(), transitionSource: DesktopModeTransitionSource, remoteTransition: RemoteTransition? = null, + callback: IMoveToDesktopCallback? = null, ) { if ( DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue() && @@ -514,6 +546,7 @@ class DesktopTasksController( remoteTransitionHandler.setTransition(transition) } else { transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource) + invokeCallbackToOverview(transition, callback) } desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted( FREEFORM_ANIMATION_DURATION @@ -524,6 +557,15 @@ class DesktopTasksController( exitResult.asExit()?.runOnTransitionStart?.invoke(transition) } + private fun invokeCallbackToOverview(transition: IBinder, callback: IMoveToDesktopCallback?) { + // TODO: b/333524374 - Remove this later. + // This is a temporary implementation for adding CUJ end and + // should be removed when animation is moved to launcher through remote transition. + if (callback != null) { + overviewToDesktopTransitionObserver.addPendingOverviewTransition(transition, callback) + } + } + /** * The first part of the animated drag to desktop transition. This is followed with a call to * [finalizeDragToDesktop] or [cancelDragToDesktop]. @@ -1446,6 +1488,7 @@ class DesktopTasksController( } private fun addLaunchHomePendingIntent(wct: WindowContainerTransaction, displayId: Int) { + val userHandle = UserHandle.of(userId) val launchHomeIntent = Intent(Intent.ACTION_MAIN).apply { if (displayId != DEFAULT_DISPLAY) { @@ -1461,11 +1504,13 @@ class DesktopTasksController( ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS } val pendingIntent = - PendingIntent.getActivity( + PendingIntent.getActivityAsUser( context, - /* requestCode = */ 0, + /* requestCode= */ 0, launchHomeIntent, PendingIntent.FLAG_IMMUTABLE, + /* options= */ null, + userHandle, ) wct.sendPendingIntent(pendingIntent, launchHomeIntent, options.toBundle()) } @@ -1819,7 +1864,9 @@ class DesktopTasksController( // need updates in some cases. val baseActivity = callingTaskInfo.baseActivity ?: return val fillIn: Intent = - context.packageManager.getLaunchIntentForPackage(baseActivity.packageName) ?: return + userProfileContexts[callingTaskInfo.userId] + ?.packageManager + ?.getLaunchIntentForPackage(baseActivity.packageName) ?: return fillIn.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK) val launchIntent = PendingIntent.getActivity( @@ -3023,12 +3070,14 @@ class DesktopTasksController( taskId: Int, transitionSource: DesktopModeTransitionSource, remoteTransition: RemoteTransition?, + callback: IMoveToDesktopCallback?, ) { executeRemoteCallWithTaskPermission(controller, "moveTaskToDesktop") { c -> c.moveTaskToDesktop( taskId, transitionSource = transitionSource, remoteTransition = remoteTransition, + callback = callback, ) } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl index ae4c2773215b..a135e4462150 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl @@ -23,6 +23,7 @@ import android.window.RemoteTransition; import com.android.wm.shell.desktopmode.IDesktopTaskListener; import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource; import com.android.wm.shell.shared.desktopmode.DesktopTaskToFrontReason; +import com.android.wm.shell.desktopmode.IMoveToDesktopCallback; /** * Interface that is exposed to remote callers to manipulate desktop mode features. @@ -58,7 +59,8 @@ interface IDesktopMode { /** Move a task with given `taskId` to desktop */ void moveToDesktop(int taskId, in DesktopModeTransitionSource transitionSource, - in @nullable RemoteTransition remoteTransition); + in @nullable RemoteTransition remoteTransition, + in @nullable IMoveToDesktopCallback callback); /** Remove desktop on the given display */ oneway void removeDesktop(int displayId); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IMoveToDesktopCallback.aidl index fc51c754e06b..6342528f9cc7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/automotive/AutoShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IMoveToDesktopCallback.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 The Android Open Source Project + * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,17 +14,9 @@ * limitations under the License. */ -package com.android.wm.shell.automotive; +package com.android.wm.shell.desktopmode; -import com.android.wm.shell.dagger.WMSingleton; +interface IMoveToDesktopCallback { -import dagger.Binds; -import dagger.Module; - - -@Module -public abstract class AutoShellModule { - @WMSingleton - @Binds - abstract AutoTaskStackController provideTaskStackController(AutoTaskStackControllerImpl impl); -} + void onTaskMovedToDesktop(); +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OverviewToDesktopTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OverviewToDesktopTransitionObserver.kt new file mode 100644 index 000000000000..873f98389723 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/OverviewToDesktopTransitionObserver.kt @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.desktopmode + +import android.os.IBinder +import android.os.RemoteException +import android.util.Slog +import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.transition.Transitions + +/** Callback to Launcher overview to notify that add to desktop from overview menu is completed. */ +class OverviewToDesktopTransitionObserver( + private val transitions: Transitions, + shellInit: ShellInit, +) : Transitions.TransitionObserver { + + private val transitionToCallback = mutableMapOf<IBinder?, IMoveToDesktopCallback?>() + + init { + shellInit.addInitCallback(::onInit, this) + } + + fun onInit() { + transitions.registerObserver(this) + } + + override fun onTransitionFinished(transition: IBinder, aborted: Boolean) { + try { + transitionToCallback[transition]?.onTaskMovedToDesktop() + transitionToCallback.clear() + } catch (e: RemoteException) { + Slog.e(TAG, "onTransitionFinished: Error calling onTaskMovedToDesktop", e) + } + } + + fun addPendingOverviewTransition(transition: IBinder?, callback: IMoveToDesktopCallback?) { + transitionToCallback += transition to callback + } + + companion object { + const val TAG = "OverviewToDesktopTransitionObserver" + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt index a428ce18a49e..2a1f524bd5d5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.desktopmode.compatui import android.animation.ValueAnimator +import android.app.ActivityManager.RunningTaskInfo import android.content.Context import android.os.IBinder import android.view.Display.DEFAULT_DISPLAY @@ -30,6 +31,7 @@ import com.android.internal.protolog.ProtoLog import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing import com.android.wm.shell.desktopmode.DesktopUserRepositories +import com.android.wm.shell.desktopmode.DesktopWallpaperActivity import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.TransitionUtil.isClosingMode import com.android.wm.shell.shared.TransitionUtil.isClosingType @@ -128,7 +130,7 @@ class SystemModalsTransitionHandler( return@find false } val taskInfo = change.taskInfo ?: return@find false - return@find isTopActivityExemptFromDesktopWindowing(context, taskInfo) + return@find isSystemModal(context, taskInfo) } private fun getClosingSystemModal(info: TransitionInfo): TransitionInfo.Change? = @@ -137,10 +139,14 @@ class SystemModalsTransitionHandler( return@find false } val taskInfo = change.taskInfo ?: return@find false - return@find isTopActivityExemptFromDesktopWindowing(context, taskInfo) || + return@find isSystemModal(context, taskInfo) || showingSystemModalsIds.contains(taskInfo.taskId) } + private fun isSystemModal(context: Context, taskInfo: RunningTaskInfo): Boolean = + !DesktopWallpaperActivity.isWallpaperTask(taskInfo) && + isTopActivityExemptFromDesktopWindowing(context, taskInfo) + private fun createAlphaAnimator( transaction: SurfaceControl.Transaction, leash: SurfaceControl, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt index 5757c6afd196..b614b3f4d025 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt @@ -22,7 +22,6 @@ import android.content.Context import android.content.res.Resources import android.graphics.Point import android.os.SystemProperties -import android.util.Slog import com.android.window.flags.Flags import com.android.wm.shell.R import com.android.wm.shell.desktopmode.CaptionState @@ -32,27 +31,17 @@ import com.android.wm.shell.shared.annotations.ShellBackgroundThread import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource -import com.android.wm.shell.windowdecor.common.DecorThemeUtil import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController.TooltipColorScheme import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController.TooltipEducationViewConfig -import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainCoroutineDispatcher -import kotlinx.coroutines.TimeoutCancellationException -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.debounce -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.take -import kotlinx.coroutines.flow.timeout import kotlinx.coroutines.launch /** @@ -72,59 +61,75 @@ class AppHandleEducationController( @ShellMainThread private val applicationCoroutineScope: CoroutineScope, @ShellBackgroundThread private val backgroundDispatcher: MainCoroutineDispatcher, ) { - private val decorThemeUtil = DecorThemeUtil(context) private lateinit var openHandleMenuCallback: (Int) -> Unit private lateinit var toDesktopModeCallback: (Int, DesktopModeTransitionSource) -> Unit + private val onTertiaryFixedColor = + context.getColor(com.android.internal.R.color.materialColorOnTertiaryFixed) + private val tertiaryFixedColor = + context.getColor(com.android.internal.R.color.materialColorTertiaryFixed) init { runIfEducationFeatureEnabled { + // Coroutine block for the first hint that appears on a full-screen app's app handle to + // encourage users to open the app handle menu. applicationCoroutineScope.launch { - // Central block handling the app handle's educational flow end-to-end. - isAppHandleHintViewedFlow() - .flatMapLatest { isAppHandleHintViewed -> - if (isAppHandleHintViewed) { - // If the education is viewed then return emptyFlow() that completes - // immediately. - // This will help us to not listen to [captionHandleStateFlow] after the - // education - // has been viewed already. - emptyFlow() - } else { - // Listen for changes to window decor's caption handle. - windowDecorCaptionHandleRepository.captionStateFlow - // Wait for few seconds before emitting the latest state. - .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS) - .filter { captionState -> - captionState is CaptionState.AppHandle && - appHandleEducationFilter.shouldShowAppHandleEducation( - captionState - ) - } - } + if (isAppHandleHintViewed()) return@launch + windowDecorCaptionHandleRepository.captionStateFlow + .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS) + .filter { captionState -> + captionState is CaptionState.AppHandle && + !captionState.isHandleMenuExpanded && + !isAppHandleHintViewed() && + appHandleEducationFilter.shouldShowDesktopModeEducation(captionState) } + .take(1) .flowOn(backgroundDispatcher) .collectLatest { captionState -> - val tooltipColorScheme = tooltipColorScheme(captionState) - - showEducation(captionState, tooltipColorScheme) - // After showing first tooltip, mark education as viewed + showEducation(captionState) appHandleEducationDatastoreRepository .updateAppHandleHintViewedTimestampMillis(true) } } + // Coroutine block for the hint that appears when an app handle is expanded to + // encourage users to enter desktop mode. applicationCoroutineScope.launch { - if (isAppHandleHintUsed()) return@launch + if (isEnterDesktopModeHintViewed()) return@launch windowDecorCaptionHandleRepository.captionStateFlow + .debounce(ENTER_DESKTOP_MODE_EDUCATION_DELAY_MILLIS) .filter { captionState -> - captionState is CaptionState.AppHandle && captionState.isHandleMenuExpanded + captionState is CaptionState.AppHandle && + captionState.isHandleMenuExpanded && + !isEnterDesktopModeHintViewed() && + appHandleEducationFilter.shouldShowDesktopModeEducation(captionState) } .take(1) .flowOn(backgroundDispatcher) - .collect { - // If user expands app handle, mark user has used the app handle hint + .collectLatest { captionState -> + showWindowingImageButtonTooltip(captionState as CaptionState.AppHandle) appHandleEducationDatastoreRepository - .updateAppHandleHintUsedTimestampMillis(true) + .updateEnterDesktopModeHintViewedTimestampMillis(true) + } + } + + // Coroutine block for the hint that appears on the window app header in freeform mode + // to let users know how to exit desktop mode. + applicationCoroutineScope.launch { + if (isExitDesktopModeHintViewed()) return@launch + windowDecorCaptionHandleRepository.captionStateFlow + .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS) + .filter { captionState -> + captionState is CaptionState.AppHeader && + !captionState.isHeaderMenuExpanded && + !isExitDesktopModeHintViewed() && + appHandleEducationFilter.shouldShowDesktopModeEducation(captionState) + } + .take(1) + .flowOn(backgroundDispatcher) + .collectLatest { captionState -> + showExitWindowingTooltip(captionState as CaptionState.AppHeader) + appHandleEducationDatastoreRepository + .updateExitDesktopModeHintViewedTimestampMillis(true) } } } @@ -135,7 +140,7 @@ class AppHandleEducationController( block() } - private fun showEducation(captionState: CaptionState, tooltipColorScheme: TooltipColorScheme) { + private fun showEducation(captionState: CaptionState) { val appHandleBounds = (captionState as CaptionState.AppHandle).globalAppHandleBounds val tooltipGlobalCoordinates = Point(appHandleBounds.left + appHandleBounds.width() / 2, appHandleBounds.bottom) @@ -145,21 +150,21 @@ class AppHandleEducationController( val appHandleTooltipConfig = TooltipEducationViewConfig( tooltipViewLayout = R.layout.desktop_windowing_education_top_arrow_tooltip, - tooltipColorScheme = tooltipColorScheme, + tooltipColorScheme = + TooltipColorScheme( + tertiaryFixedColor, + onTertiaryFixedColor, + onTertiaryFixedColor, + ), tooltipViewGlobalCoordinates = tooltipGlobalCoordinates, tooltipText = getString(R.string.windowing_app_handle_education_tooltip), arrowDirection = DesktopWindowingEducationTooltipController.TooltipArrowDirection.UP, onEducationClickAction = { - launchWithExceptionHandling { - showWindowingImageButtonTooltip(tooltipColorScheme) - } openHandleMenuCallback(captionState.runningTaskInfo.taskId) }, onDismissAction = { - launchWithExceptionHandling { - showWindowingImageButtonTooltip(tooltipColorScheme) - } + // TODO: b/341320146 - Log previous tooltip was dismissed }, ) @@ -170,7 +175,7 @@ class AppHandleEducationController( } /** Show tooltip that points to windowing image button in app handle menu */ - private suspend fun showWindowingImageButtonTooltip(tooltipColorScheme: TooltipColorScheme) { + private suspend fun showWindowingImageButtonTooltip(captionState: CaptionState.AppHandle) { val appInfoPillHeight = getSize(R.dimen.desktop_mode_handle_menu_app_info_pill_height) val windowingOptionPillHeight = getSize(R.dimen.desktop_mode_handle_menu_windowing_pill_height) @@ -181,128 +186,81 @@ class AppHandleEducationController( getSize(R.dimen.desktop_mode_handle_menu_margin_top) + getSize(R.dimen.desktop_mode_handle_menu_pill_spacing_margin) - windowDecorCaptionHandleRepository.captionStateFlow - // After the first tooltip was dismissed, wait for 400 ms and see if the app handle menu - // has been expanded. - .timeout(APP_HANDLE_EDUCATION_TIMEOUT_MILLIS.milliseconds) - .catchTimeoutAndLog { - // TODO: b/341320146 - Log previous tooltip was dismissed - } - // Wait for few milliseconds before emitting the latest state. - .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS) - .filter { captionState -> - // Filter out states when app handle is not visible or not expanded. - captionState is CaptionState.AppHandle && captionState.isHandleMenuExpanded - } - // Before showing this tooltip, stop listening to further emissions to avoid - // accidentally - // showing the same tooltip on future emissions. - .take(1) - .flowOn(backgroundDispatcher) - .collectLatest { captionState -> - captionState as CaptionState.AppHandle - val appHandleBounds = captionState.globalAppHandleBounds - val tooltipGlobalCoordinates = - Point( - appHandleBounds.left + appHandleBounds.width() / 2 + appHandleMenuWidth / 2, - appHandleBounds.top + - appHandleMenuMargins + - appInfoPillHeight + - windowingOptionPillHeight / 2, - ) - // Populate information important to inflate windowing image button education - // tooltip. - val windowingImageButtonTooltipConfig = - TooltipEducationViewConfig( - tooltipViewLayout = R.layout.desktop_windowing_education_left_arrow_tooltip, - tooltipColorScheme = tooltipColorScheme, - tooltipViewGlobalCoordinates = tooltipGlobalCoordinates, - tooltipText = - getString( - R.string.windowing_desktop_mode_image_button_education_tooltip - ), - arrowDirection = - DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT, - onEducationClickAction = { - launchWithExceptionHandling { - showExitWindowingTooltip(tooltipColorScheme) - } - toDesktopModeCallback( - captionState.runningTaskInfo.taskId, - DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON, - ) - }, - onDismissAction = { - launchWithExceptionHandling { - showExitWindowingTooltip(tooltipColorScheme) - } - }, + val appHandleBounds = captionState.globalAppHandleBounds + val tooltipGlobalCoordinates = + Point( + appHandleBounds.left + appHandleBounds.width() / 2 + appHandleMenuWidth / 2, + appHandleBounds.top + + appHandleMenuMargins + + appInfoPillHeight + + windowingOptionPillHeight / 2, + ) + // Populate information important to inflate windowing image button education + // tooltip. + val windowingImageButtonTooltipConfig = + TooltipEducationViewConfig( + tooltipViewLayout = R.layout.desktop_windowing_education_left_arrow_tooltip, + tooltipColorScheme = + TooltipColorScheme( + tertiaryFixedColor, + onTertiaryFixedColor, + onTertiaryFixedColor, + ), + tooltipViewGlobalCoordinates = tooltipGlobalCoordinates, + tooltipText = + getString(R.string.windowing_desktop_mode_image_button_education_tooltip), + arrowDirection = + DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT, + onEducationClickAction = { + toDesktopModeCallback( + captionState.runningTaskInfo.taskId, + DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON, ) + }, + onDismissAction = { + // TODO: b/341320146 - Log previous tooltip was dismissed + }, + ) - windowingEducationViewController.showEducationTooltip( - taskId = captionState.runningTaskInfo.taskId, - tooltipViewConfig = windowingImageButtonTooltipConfig, - ) - } + windowingEducationViewController.showEducationTooltip( + taskId = captionState.runningTaskInfo.taskId, + tooltipViewConfig = windowingImageButtonTooltipConfig, + ) } /** Show tooltip that points to app chip button and educates user on how to exit desktop mode */ - private suspend fun showExitWindowingTooltip(tooltipColorScheme: TooltipColorScheme) { - windowDecorCaptionHandleRepository.captionStateFlow - // After the previous tooltip was dismissed, wait for 400 ms and see if the user entered - // desktop mode. - .timeout(APP_HANDLE_EDUCATION_TIMEOUT_MILLIS.milliseconds) - .catchTimeoutAndLog { - // TODO: b/341320146 - Log previous tooltip was dismissed - } - // Wait for few milliseconds before emitting the latest state. - .debounce(APP_HANDLE_EDUCATION_DELAY_MILLIS) - .filter { captionState -> - // Filter out states when app header is not visible or expanded. - captionState is CaptionState.AppHeader && !captionState.isHeaderMenuExpanded - } - // Before showing this tooltip, stop listening to further emissions to avoid - // accidentally - // showing the same tooltip on future emissions. - .take(1) - .flowOn(backgroundDispatcher) - .collectLatest { captionState -> - captionState as CaptionState.AppHeader - val globalAppChipBounds = captionState.globalAppChipBounds - val tooltipGlobalCoordinates = - Point( - globalAppChipBounds.right, - globalAppChipBounds.top + globalAppChipBounds.height() / 2, - ) - // Populate information important to inflate exit desktop mode education tooltip. - val exitWindowingTooltipConfig = - TooltipEducationViewConfig( - tooltipViewLayout = R.layout.desktop_windowing_education_left_arrow_tooltip, - tooltipColorScheme = tooltipColorScheme, - tooltipViewGlobalCoordinates = tooltipGlobalCoordinates, - tooltipText = - getString(R.string.windowing_desktop_mode_exit_education_tooltip), - arrowDirection = - DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT, - onDismissAction = {}, - onEducationClickAction = { - openHandleMenuCallback(captionState.runningTaskInfo.taskId) - }, - ) - windowingEducationViewController.showEducationTooltip( - taskId = captionState.runningTaskInfo.taskId, - tooltipViewConfig = exitWindowingTooltipConfig, - ) - } - } - - private fun tooltipColorScheme(captionState: CaptionState): TooltipColorScheme { - val onTertiaryFixed = - context.getColor(com.android.internal.R.color.materialColorOnTertiaryFixed) - val tertiaryFixed = - context.getColor(com.android.internal.R.color.materialColorTertiaryFixed) - - return TooltipColorScheme(tertiaryFixed, onTertiaryFixed, onTertiaryFixed) + private suspend fun showExitWindowingTooltip(captionState: CaptionState.AppHeader) { + val globalAppChipBounds = captionState.globalAppChipBounds + val tooltipGlobalCoordinates = + Point( + globalAppChipBounds.right, + globalAppChipBounds.top + globalAppChipBounds.height() / 2, + ) + // Populate information important to inflate exit desktop mode education tooltip. + val exitWindowingTooltipConfig = + TooltipEducationViewConfig( + tooltipViewLayout = R.layout.desktop_windowing_education_left_arrow_tooltip, + tooltipColorScheme = + TooltipColorScheme( + tertiaryFixedColor, + onTertiaryFixedColor, + onTertiaryFixedColor, + ), + tooltipViewGlobalCoordinates = tooltipGlobalCoordinates, + tooltipText = getString(R.string.windowing_desktop_mode_exit_education_tooltip), + arrowDirection = + DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT, + onDismissAction = { + // TODO: b/341320146 - Log previous tooltip was dismissed + }, + onEducationClickAction = { + openHandleMenuCallback(captionState.runningTaskInfo.taskId) + }, + ) + windowingEducationViewController.showEducationTooltip( + taskId = captionState.runningTaskInfo.taskId, + tooltipViewConfig = exitWindowingTooltipConfig, + ) } /** @@ -319,43 +277,20 @@ class AppHandleEducationController( this.toDesktopModeCallback = toDesktopModeCallback } - private inline fun <T> Flow<T>.catchTimeoutAndLog(crossinline block: () -> Unit) = - catch { exception -> - if (exception is TimeoutCancellationException) block() else throw exception - } - - private fun launchWithExceptionHandling(block: suspend () -> Unit) = - applicationCoroutineScope.launch { - try { - block() - } catch (e: Throwable) { - Slog.e(TAG, "Error: ", e) - } - } + private suspend fun isAppHandleHintViewed(): Boolean = + appHandleEducationDatastoreRepository.dataStoreFlow + .first() + .hasAppHandleHintViewedTimestampMillis() && !FORCE_SHOW_DESKTOP_MODE_EDUCATION - /** - * Listens to the changes to [WindowingEducationProto#hasAppHandleHintViewedTimestampMillis()] - * in datastore proto object. - * - * If [SHOULD_OVERRIDE_EDUCATION_CONDITIONS] is true, this flow will always emit false. That - * means it will always emit app handle hint has not been viewed yet. - */ - private fun isAppHandleHintViewedFlow(): Flow<Boolean> = + private suspend fun isEnterDesktopModeHintViewed(): Boolean = appHandleEducationDatastoreRepository.dataStoreFlow - .map { preferences -> - preferences.hasAppHandleHintViewedTimestampMillis() && - !SHOULD_OVERRIDE_EDUCATION_CONDITIONS - } - .distinctUntilChanged() + .first() + .hasEnterDesktopModeHintViewedTimestampMillis() && !FORCE_SHOW_DESKTOP_MODE_EDUCATION - /** - * Listens to the changes to [WindowingEducationProto#hasAppHandleHintUsedTimestampMillis()] in - * datastore proto object. - */ - private suspend fun isAppHandleHintUsed(): Boolean = + private suspend fun isExitDesktopModeHintViewed(): Boolean = appHandleEducationDatastoreRepository.dataStoreFlow .first() - .hasAppHandleHintUsedTimestampMillis() + .hasExitDesktopModeHintViewedTimestampMillis() && !FORCE_SHOW_DESKTOP_MODE_EDUCATION private fun getSize(@DimenRes resourceId: Int): Int { if (resourceId == Resources.ID_NULL) return 0 @@ -369,13 +304,17 @@ class AppHandleEducationController( val APP_HANDLE_EDUCATION_DELAY_MILLIS: Long get() = SystemProperties.getLong("persist.windowing_app_handle_education_delay", 3000L) - val APP_HANDLE_EDUCATION_TIMEOUT_MILLIS: Long - get() = SystemProperties.getLong("persist.windowing_app_handle_education_timeout", 400L) + val ENTER_DESKTOP_MODE_EDUCATION_DELAY_MILLIS: Long + get() = + SystemProperties.getLong( + "persist.windowing_enter_desktop_mode_education_timeout", + 400L, + ) - val SHOULD_OVERRIDE_EDUCATION_CONDITIONS: Boolean + val FORCE_SHOW_DESKTOP_MODE_EDUCATION: Boolean get() = SystemProperties.getBoolean( - "persist.desktop_windowing_app_handle_education_override_conditions", + "persist.windowing_force_show_desktop_mode_education", false, ) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt index 9990846fc92e..4d219b5544aa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilter.kt @@ -17,13 +17,14 @@ package com.android.wm.shell.desktopmode.education import android.annotation.IntegerRes +import android.app.ActivityManager.RunningTaskInfo import android.app.usage.UsageStatsManager import android.content.Context import android.os.SystemClock import android.provider.Settings.Secure import com.android.wm.shell.R import com.android.wm.shell.desktopmode.CaptionState -import com.android.wm.shell.desktopmode.education.AppHandleEducationController.Companion.SHOULD_OVERRIDE_EDUCATION_CONDITIONS +import com.android.wm.shell.desktopmode.education.AppHandleEducationController.Companion.FORCE_SHOW_DESKTOP_MODE_EDUCATION import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatastoreRepository import com.android.wm.shell.desktopmode.education.data.WindowingEducationProto import java.time.Duration @@ -37,26 +38,28 @@ class AppHandleEducationFilter( private val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager + suspend fun shouldShowDesktopModeEducation(captionState: CaptionState.AppHeader): Boolean = + shouldShowDesktopModeEducation(captionState.runningTaskInfo) + + suspend fun shouldShowDesktopModeEducation(captionState: CaptionState.AppHandle): Boolean = + shouldShowDesktopModeEducation(captionState.runningTaskInfo) + /** - * Returns true if conditions to show app handle education are met, returns false otherwise. + * Returns true if conditions to show app handle, enter desktop mode and exit desktop mode + * education are met based on the app info and usage, returns false otherwise. * - * If [SHOULD_OVERRIDE_EDUCATION_CONDITIONS] is true, this method will always return - * ![captionState.isHandleMenuExpanded]. + * If [FORCE_SHOW_DESKTOP_MODE_EDUCATION] is true, this method will always return true. */ - suspend fun shouldShowAppHandleEducation(captionState: CaptionState): Boolean { - if ((captionState as CaptionState.AppHandle).isHandleMenuExpanded) return false - if (SHOULD_OVERRIDE_EDUCATION_CONDITIONS) return true + private suspend fun shouldShowDesktopModeEducation(taskInfo: RunningTaskInfo): Boolean { + if (FORCE_SHOW_DESKTOP_MODE_EDUCATION) return true - val focusAppPackageName = - captionState.runningTaskInfo.topActivityInfo?.packageName ?: return false + val focusAppPackageName = taskInfo.topActivityInfo?.packageName ?: return false val windowingEducationProto = appHandleEducationDatastoreRepository.windowingEducationProto() return isFocusAppInAllowlist(focusAppPackageName) && !isOtherEducationShowing() && hasSufficientTimeSinceSetup() && - !isAppHandleHintViewedBefore(windowingEducationProto) && - !isAppHandleHintUsedBefore(windowingEducationProto) && hasMinAppUsage(windowingEducationProto, focusAppPackageName) } @@ -79,14 +82,6 @@ class AppHandleEducationFilter( R.integer.desktop_windowing_education_required_time_since_setup_seconds ) - private fun isAppHandleHintViewedBefore( - windowingEducationProto: WindowingEducationProto - ): Boolean = windowingEducationProto.hasAppHandleHintViewedTimestampMillis() - - private fun isAppHandleHintUsedBefore( - windowingEducationProto: WindowingEducationProto - ): Boolean = windowingEducationProto.hasAppHandleHintUsedTimestampMillis() - private suspend fun hasMinAppUsage( windowingEducationProto: WindowingEducationProto, focusAppPackageName: String, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt index 3e120b09a0b6..d061e03b9be5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/data/AppHandleEducationDatastoreRepository.kt @@ -91,6 +91,40 @@ constructor(private val dataStore: DataStore<WindowingEducationProto>) { } /** + * Updates [WindowingEducationProto.enterDesktopModeHintViewedTimestampMillis_] field in + * datastore with current timestamp if [isViewed] is true, if not then clears the field. + */ + suspend fun updateEnterDesktopModeHintViewedTimestampMillis(isViewed: Boolean) { + dataStore.updateData { preferences -> + if (isViewed) { + preferences + .toBuilder() + .setEnterDesktopModeHintViewedTimestampMillis(System.currentTimeMillis()) + .build() + } else { + preferences.toBuilder().clearEnterDesktopModeHintViewedTimestampMillis().build() + } + } + } + + /** + * Updates [WindowingEducationProto.exitDesktopModeHintViewedTimestampMillis_] field in + * datastore with current timestamp if [isViewed] is true, if not then clears the field. + */ + suspend fun updateExitDesktopModeHintViewedTimestampMillis(isViewed: Boolean) { + dataStore.updateData { preferences -> + if (isViewed) { + preferences + .toBuilder() + .setExitDesktopModeHintViewedTimestampMillis(System.currentTimeMillis()) + .build() + } else { + preferences.toBuilder().clearExitDesktopModeHintViewedTimestampMillis().build() + } + } + } + + /** * Updates [WindowingEducationProto.appHandleHintUsedTimestampMillis_] field in datastore with * current timestamp if [isViewed] is true, if not then clears the field. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt new file mode 100644 index 000000000000..5cbb59fbf323 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.desktopmode.multidesks + +import android.app.ActivityManager +import android.window.TransitionInfo +import android.window.WindowContainerTransaction + +/** An organizer of desk containers in which to host child desktop windows. */ +interface DesksOrganizer { + /** Creates a new desk container in the given display. */ + fun createDesk(displayId: Int, callback: OnCreateCallback) + + /** Activates the given desk, making it visible in its display. */ + fun activateDesk(wct: WindowContainerTransaction, deskId: Int) + + /** Removes the given desk and its desktop windows. */ + fun removeDesk(wct: WindowContainerTransaction, deskId: Int) + + /** Moves the given task to the given desk. */ + fun moveTaskToDesk( + wct: WindowContainerTransaction, + deskId: Int, + task: ActivityManager.RunningTaskInfo, + ) + + /** + * Returns the desk id in which the task in the given change is located at the end of a + * transition, if any. + */ + fun getDeskAtEnd(change: TransitionInfo.Change): Int? + + /** A callback that is invoked when the desk container is created. */ + fun interface OnCreateCallback { + /** Calls back when the [deskId] has been created. */ + fun onCreated(deskId: Int) + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/OnDeskRemovedListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/OnDeskRemovedListener.kt new file mode 100644 index 000000000000..452ddb1ff8fb --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/OnDeskRemovedListener.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.desktopmode.multidesks + +/** A listener for removals of desks. */ +fun interface OnDeskRemovedListener { + /** Called when a desk has been removed from the system. */ + fun onDeskRemoved(lastDisplayId: Int, deskId: Int) +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt new file mode 100644 index 000000000000..79c48c5e9594 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.desktopmode.multidesks + +import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD +import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED +import android.util.SparseArray +import android.view.SurfaceControl +import android.window.TransitionInfo +import android.window.WindowContainerTransaction +import androidx.core.util.forEach +import com.android.internal.annotations.VisibleForTesting +import com.android.internal.protolog.ProtoLog +import com.android.window.flags.Flags +import com.android.wm.shell.ShellTaskOrganizer +import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer.OnCreateCallback +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE +import com.android.wm.shell.sysui.ShellCommandHandler +import com.android.wm.shell.sysui.ShellInit +import java.io.PrintWriter + +/** A [DesksOrganizer] that uses root tasks as the container of each desk. */ +class RootTaskDesksOrganizer( + shellInit: ShellInit, + shellCommandHandler: ShellCommandHandler, + private val shellTaskOrganizer: ShellTaskOrganizer, +) : DesksOrganizer, ShellTaskOrganizer.TaskListener { + + private val deskCreateRequests = mutableListOf<CreateRequest>() + @VisibleForTesting val roots = SparseArray<DeskRoot>() + + init { + if (Flags.enableMultipleDesktopsBackend()) { + shellInit.addInitCallback( + { shellCommandHandler.addDumpCallback(this::dump, this) }, + this, + ) + } + } + + override fun createDesk(displayId: Int, callback: OnCreateCallback) { + logV("createDesk in display: %d", displayId) + deskCreateRequests += CreateRequest(displayId, callback) + shellTaskOrganizer.createRootTask( + displayId, + WINDOWING_MODE_FREEFORM, + /* listener = */ this, + /* removeWithTaskOrganizer = */ true, + ) + } + + override fun removeDesk(wct: WindowContainerTransaction, deskId: Int) { + logV("removeDesk %d", deskId) + val desk = checkNotNull(roots[deskId]) { "Root not found for desk: $deskId" } + wct.removeRootTask(desk.taskInfo.token) + } + + override fun activateDesk(wct: WindowContainerTransaction, deskId: Int) { + logV("activateDesk %d", deskId) + val root = checkNotNull(roots[deskId]) { "Root not found for desk: $deskId" } + wct.reorder(root.taskInfo.token, /* onTop= */ true) + wct.setLaunchRoot( + /* container= */ root.taskInfo.token, + /* windowingModes= */ intArrayOf(WINDOWING_MODE_FREEFORM, WINDOWING_MODE_UNDEFINED), + /* activityTypes= */ intArrayOf(ACTIVITY_TYPE_UNDEFINED, ACTIVITY_TYPE_STANDARD), + ) + } + + override fun moveTaskToDesk( + wct: WindowContainerTransaction, + deskId: Int, + task: RunningTaskInfo, + ) { + val root = roots[deskId] ?: error("Root not found for desk: $deskId") + wct.reparent(task.token, root.taskInfo.token, /* onTop= */ true) + } + + override fun getDeskAtEnd(change: TransitionInfo.Change): Int? = + change.taskInfo?.parentTaskId?.takeIf { it in roots } + + override fun onTaskAppeared(taskInfo: RunningTaskInfo, leash: SurfaceControl) { + if (taskInfo.parentTaskId in roots) { + val deskId = taskInfo.parentTaskId + val taskId = taskInfo.taskId + logV("Task #$taskId appeared in desk #$deskId") + addChildToDesk(taskId = taskId, deskId = deskId) + return + } + val deskId = taskInfo.taskId + check(deskId !in roots) { "A root already exists for desk: $deskId" } + val request = + checkNotNull(deskCreateRequests.firstOrNull { it.displayId == taskInfo.displayId }) { + "Task ${taskInfo.taskId} appeared without pending create request" + } + logV("Desk #$deskId appeared") + roots[deskId] = DeskRoot(deskId, taskInfo, leash) + deskCreateRequests.remove(request) + request.onCreateCallback.onCreated(deskId) + } + + override fun onTaskInfoChanged(taskInfo: RunningTaskInfo) { + if (roots.contains(taskInfo.taskId)) { + val deskId = taskInfo.taskId + roots[deskId] = roots[deskId].copy(taskInfo = taskInfo) + } + } + + override fun onTaskVanished(taskInfo: RunningTaskInfo) { + if (roots.contains(taskInfo.taskId)) { + val deskId = taskInfo.taskId + val deskRoot = roots[deskId] + // Use the last saved taskInfo to obtain the displayId. Using the local one here will + // return -1 since the task is not unassociated with a display. + val displayId = deskRoot.taskInfo.displayId + logV("Desk #$deskId vanished from display #$displayId") + roots.remove(deskId) + return + } + // At this point, [parentTaskId] may be unset even if this is a task vanishing from a desk, + // so search through each root to remove this if it's a child. + roots.forEach { deskId, deskRoot -> + if (deskRoot.children.remove(taskInfo.taskId)) { + logV("Task #${taskInfo.taskId} vanished from desk #$deskId") + return + } + } + } + + @VisibleForTesting + data class DeskRoot( + val deskId: Int, + val taskInfo: RunningTaskInfo, + val leash: SurfaceControl, + val children: MutableSet<Int> = mutableSetOf(), + ) + + override fun dump(pw: PrintWriter, prefix: String) { + val innerPrefix = "$prefix " + pw.println("$prefix$TAG") + pw.println("${innerPrefix}Desk Roots:") + roots.forEach { deskId, root -> + pw.println("$innerPrefix #$deskId visible=${root.taskInfo.isVisible}") + pw.println("$innerPrefix children=${root.children}") + } + } + + private fun addChildToDesk(taskId: Int, deskId: Int) { + roots.forEach { _, deskRoot -> + if (deskRoot.deskId == deskId) { + deskRoot.children.add(taskId) + } else { + deskRoot.children.remove(taskId) + } + } + } + + private data class CreateRequest(val displayId: Int, val onCreateCallback: OnCreateCallback) + + private fun logV(msg: String, vararg arguments: Any?) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + companion object { + private const val TAG = "RootTaskDesksOrganizer" + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt index 58a49a035bb6..5a89451ffdbc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt @@ -18,6 +18,7 @@ package com.android.wm.shell.desktopmode.persistence import android.content.Context import android.window.DesktopModeFlags +import com.android.window.flags.Flags import com.android.wm.shell.desktopmode.DesktopRepository import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.shared.annotations.ShellMainThread @@ -54,10 +55,22 @@ class DesktopRepositoryInitializerImpl( DesktopModeStatus.getMaxTaskLimit(context).takeIf { it > 0 } ?: persistentDesktop.zOrderedTasksCount var visibleTasksCount = 0 + repository.addDesk( + displayId = persistentDesktop.displayId, + deskId = + if (Flags.enableMultipleDesktopsBackend()) { + persistentDesktop.desktopId + } else { + // When disabled, desk ids are always the display id. + persistentDesktop.displayId + }, + ) persistentDesktop.zOrderedTasksList // Reverse it so we initialize the repo from bottom to top. .reversed() .mapNotNull { taskId -> persistentDesktop.tasksByTaskIdMap[taskId] } + // TODO: b/362720497 - add tasks to their respective desk when multi-desk + // persistence is implemented. .forEach { task -> if ( task.desktopTaskState == DesktopTaskState.VISIBLE && diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java index 0d5aa0105659..897e2d1601a5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java @@ -29,6 +29,7 @@ import android.window.DesktopModeFlags; import com.android.internal.protolog.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.LaunchAdjacentController; +import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.desktopmode.DesktopUserRepositories; @@ -52,6 +53,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, private final ShellTaskOrganizer mShellTaskOrganizer; private final Optional<DesktopUserRepositories> mDesktopUserRepositories; private final Optional<DesktopTasksController> mDesktopTasksController; + private final DesktopModeLoggerTransitionObserver mDesktopModeLoggerTransitionObserver; private final WindowDecorViewModel mWindowDecorationViewModel; private final LaunchAdjacentController mLaunchAdjacentController; private final Optional<TaskChangeListener> mTaskChangeListener; @@ -64,6 +66,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, ShellTaskOrganizer shellTaskOrganizer, Optional<DesktopUserRepositories> desktopUserRepositories, Optional<DesktopTasksController> desktopTasksController, + DesktopModeLoggerTransitionObserver desktopModeLoggerTransitionObserver, LaunchAdjacentController launchAdjacentController, WindowDecorViewModel windowDecorationViewModel, Optional<TaskChangeListener> taskChangeListener) { @@ -72,6 +75,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, mWindowDecorationViewModel = windowDecorationViewModel; mDesktopUserRepositories = desktopUserRepositories; mDesktopTasksController = desktopTasksController; + mDesktopModeLoggerTransitionObserver = desktopModeLoggerTransitionObserver; mLaunchAdjacentController = launchAdjacentController; mTaskChangeListener = taskChangeListener; if (shellInit != null) { @@ -130,6 +134,9 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, repository.removeTask(taskInfo.displayId, taskInfo.taskId); } } + // TODO: b/367268649 - This listener shouldn't need to call the transition observer directly + // for logging once the logic in the observer is moved. + mDesktopModeLoggerTransitionObserver.onTaskVanished(taskInfo); mWindowDecorationViewModel.onTaskVanished(taskInfo); updateLaunchAdjacentController(); } @@ -171,7 +178,8 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, @Override public void onFocusTaskChanged(RunningTaskInfo taskInfo) { - if (taskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM) { + if (taskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM + || DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue()) { return; } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java index bec75b3d865c..20b8c5ec45ce 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java @@ -21,6 +21,9 @@ import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; +import static com.android.wm.shell.pip.PipTransitionController.ANIM_TYPE_ALPHA; +import static com.android.wm.shell.pip.PipTransitionController.ANIM_TYPE_BOUNDS; + import android.animation.AnimationHandler; import android.animation.Animator; import android.animation.RectEvaluator; @@ -59,16 +62,6 @@ public class PipAnimationController { static final float FRACTION_START = 0f; static final float FRACTION_END = 1f; - public static final int ANIM_TYPE_BOUNDS = 0; - public static final int ANIM_TYPE_ALPHA = 1; - - @IntDef(prefix = { "ANIM_TYPE_" }, value = { - ANIM_TYPE_BOUNDS, - ANIM_TYPE_ALPHA - }) - @Retention(RetentionPolicy.SOURCE) - public @interface AnimationType {} - /** * The alpha type is set for swiping to home. But the swiped task may not enter PiP. And if * another task enters PiP by non-swipe ways, e.g. call API in foreground or switch to 3-button @@ -125,7 +118,7 @@ public class PipAnimationController { }); private PipTransitionAnimator mCurrentAnimator; - @AnimationType + @PipTransitionController.AnimationType private int mOneShotAnimationType = ANIM_TYPE_BOUNDS; private long mLastOneShotAlphaAnimationTime; @@ -157,9 +150,9 @@ public class PipAnimationController { /** * Construct and return an animator that animates from the {@param startBounds} to the * {@param endBounds} with the given {@param direction}. If {@param direction} is type - * {@link ANIM_TYPE_BOUNDS}, then {@param sourceHintRect} will be used to animate - * in a better, more smooth manner. If the original bound was rotated and a reset needs to - * happen, pass in {@param startingAngle}. + * {@link PipTransitionController#ANIM_TYPE_BOUNDS}, then {@param sourceHintRect} will be used + * to animate in a better, more smooth manner. If the original bound was rotated and a reset + * needs to happen, pass in {@param startingAngle}. * * In the case where one wants to start animation during an intermediate animation (for example, * if the user is currently doing a pinch-resize, and upon letting go now PiP needs to animate @@ -244,12 +237,13 @@ public class PipAnimationController { /** * Sets the preferred enter animation type for one time. This is typically used to set the - * animation type to {@link PipAnimationController#ANIM_TYPE_ALPHA}. + * animation type to {@link PipTransitionController#ANIM_TYPE_ALPHA}. * <p> * For example, gesture navigation would first fade out the PiP activity, and the transition * should be responsible to animate in (such as fade in) the PiP. */ - public void setOneShotEnterAnimationType(@AnimationType int animationType) { + public void setOneShotEnterAnimationType( + @PipTransitionController.AnimationType int animationType) { mOneShotAnimationType = animationType; if (animationType == ANIM_TYPE_ALPHA) { mLastOneShotAlphaAnimationTime = SystemClock.uptimeMillis(); @@ -257,7 +251,7 @@ public class PipAnimationController { } /** Returns the preferred animation type and consumes the one-shot type if needed. */ - @AnimationType + @PipTransitionController.AnimationType public int takeOneShotEnterAnimationType() { final int type = mOneShotAnimationType; if (type == ANIM_TYPE_ALPHA) { @@ -321,7 +315,7 @@ public class PipAnimationController { ValueAnimator.AnimatorListener { private final TaskInfo mTaskInfo; private final SurfaceControl mLeash; - private final @AnimationType int mAnimationType; + private final @PipTransitionController.AnimationType int mAnimationType; private final Rect mDestinationBounds = new Rect(); private final Point mLeashOffset = new Point(); @@ -341,16 +335,17 @@ public class PipAnimationController { private boolean mHasRequestedEnd; private PipTransitionAnimator(@NonNull TaskInfo taskInfo, @NonNull SurfaceControl leash, - @AnimationType int animationType, @NonNull Rect destinationBounds, - @NonNull T baseValue, @NonNull T startValue, @NonNull T endValue) { + @PipTransitionController.AnimationType int animationType, + @NonNull Rect destinationBounds, @NonNull T baseValue, @NonNull T startValue, + @NonNull T endValue) { this(taskInfo, leash, animationType, destinationBounds, new Point(), baseValue, startValue, endValue); } private PipTransitionAnimator(@NonNull TaskInfo taskInfo, @NonNull SurfaceControl leash, - @AnimationType int animationType, @NonNull Rect destinationBounds, - @NonNull Point leashOffset, @NonNull T baseValue, @NonNull T startValue, - @NonNull T endValue) { + @PipTransitionController.AnimationType int animationType, + @NonNull Rect destinationBounds, @NonNull Point leashOffset, + @NonNull T baseValue, @NonNull T startValue, @NonNull T endValue) { mTaskInfo = taskInfo; mLeash = leash; mAnimationType = animationType; @@ -408,7 +403,8 @@ public class PipAnimationController { @Override public void onAnimationRepeat(Animator animation) {} @VisibleForTesting - @AnimationType public int getAnimationType() { + @PipTransitionController.AnimationType + public int getAnimationType() { return mAnimationType; } 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 af187682d379..61a193c7d523 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 @@ -28,8 +28,6 @@ import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP; import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString; import static com.android.wm.shell.desktopmode.DesktopModeUtils.calculateInitialBounds; import static com.android.wm.shell.desktopmode.DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE; -import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; -import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS; import static com.android.wm.shell.pip.PipAnimationController.FRACTION_START; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP; @@ -43,6 +41,8 @@ import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTI import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection; import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection; import static com.android.wm.shell.pip.PipAnimationController.isRemovePipDirection; +import static com.android.wm.shell.pip.PipTransitionController.ANIM_TYPE_ALPHA; +import static com.android.wm.shell.pip.PipTransitionController.ANIM_TYPE_BOUNDS; import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS; @@ -1716,7 +1716,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, - @PipAnimationController.AnimationType int type) { + @PipTransitionController.AnimationType int type) { final Rect preResizeBounds = new Rect(mPipBoundsState.getBounds()); mPipBoundsState.setBounds(destinationBounds); if (direction == TRANSITION_DIRECTION_REMOVE_STACK) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index bba778d9f438..2f3c15208621 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -32,8 +32,6 @@ import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.window.TransitionInfo.FLAG_IS_DISPLAY; -import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; -import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SAME; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP; @@ -116,7 +114,7 @@ public class PipTransition extends PipTransitionController { private final HomeTransitionObserver mHomeTransitionObserver; private final Optional<SplitScreenController> mSplitScreenOptional; private final PipAnimationController mPipAnimationController; - private @PipAnimationController.AnimationType int mEnterAnimationType = ANIM_TYPE_BOUNDS; + private @AnimationType int mEnterAnimationType = ANIM_TYPE_BOUNDS; private Transitions.TransitionFinishCallback mFinishCallback; private SurfaceControl.Transaction mFinishTransaction; private final Rect mExitDestinationBounds = new Rect(); @@ -992,7 +990,7 @@ public class PipTransition extends PipTransitionController { } @Override - public void setEnterAnimationType(@PipAnimationController.AnimationType int type) { + public void setEnterAnimationType(@AnimationType int type) { mEnterAnimationType = type; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java index 91150b0070ce..da3181096d98 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java @@ -23,6 +23,7 @@ import static android.view.WindowManager.TRANSIT_PIP; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK; import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection; +import android.annotation.IntDef; import android.annotation.Nullable; import android.app.ActivityTaskManager; import android.app.Flags; @@ -55,6 +56,8 @@ import com.android.wm.shell.transition.DefaultMixedHandler; import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executor; @@ -73,6 +76,17 @@ public abstract class PipTransitionController implements Transitions.TransitionH protected PipTaskOrganizer mPipOrganizer; protected DefaultMixedHandler mMixedHandler; + public static final int ANIM_TYPE_BOUNDS = 0; + public static final int ANIM_TYPE_ALPHA = 1; + + @IntDef(prefix = { "ANIM_TYPE_" }, value = { + ANIM_TYPE_BOUNDS, + ANIM_TYPE_ALPHA + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AnimationType {} + + protected final PipAnimationController.PipAnimationCallback mPipAnimationCallback = new PipAnimationController.PipAnimationCallback() { @Override @@ -357,7 +371,7 @@ public abstract class PipTransitionController implements Transitions.TransitionH } /** Sets the type of animation when a PiP task appears. */ - public void setEnterAnimationType(@PipAnimationController.AnimationType int type) { + public void setEnterAnimationType(@AnimationType int type) { } /** Play a transition animation for entering PiP on a specific PiP change. */ 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 912d3839fae7..9cf822b32a74 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 @@ -22,7 +22,6 @@ import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static android.view.WindowManager.INPUT_CONSUMER_PIP; import static com.android.internal.jank.InteractionJankMonitor.CUJ_PIP_TRANSITION; -import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN; @@ -32,6 +31,7 @@ import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTI import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE; import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection; +import static com.android.wm.shell.pip.PipTransitionController.ANIM_TYPE_ALPHA; import android.app.ActivityManager; import android.app.ActivityTaskManager; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index 8cba076d28f2..272cb4372acf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -141,6 +141,8 @@ public class PipTransition extends PipTransitionController implements private ValueAnimator mTransitionAnimator; + private @AnimationType int mEnterAnimationType = ANIM_TYPE_BOUNDS; + public PipTransition( Context context, @NonNull ShellInit shellInit, @@ -812,12 +814,11 @@ public class PipTransition extends PipTransitionController implements if (TransitionUtil.isOpeningType(info.getType())) { for (TransitionInfo.Change change : info.getChanges()) { if (change.getLeash() == null) continue; - if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) { + if (TransitionUtil.isOpeningMode(change.getMode())) { startTransaction.setAlpha(change.getLeash(), 1f); } } } - } private WindowContainerTransaction getEnterPipTransaction(@NonNull IBinder transition, @@ -901,10 +902,19 @@ public class PipTransition extends PipTransitionController implements private boolean isLegacyEnter(@NonNull TransitionInfo info) { TransitionInfo.Change pipChange = getPipChange(info); - // If the only change in the changes list is a opening type PiP task, - // then this is legacy-enter PiP. - return pipChange != null && info.getChanges().size() == 1 - && (pipChange.getMode() == TRANSIT_TO_FRONT || pipChange.getMode() == TRANSIT_OPEN); + if (pipChange != null) { + if (mEnterAnimationType == ANIM_TYPE_ALPHA) { + // If enter animation type is force overridden to an alpha type, + // treat this as legacy, and reset the animation type to default (i.e. bounds type). + setEnterAnimationType(ANIM_TYPE_BOUNDS); + return true; + } + // If the only change in the changes list is a opening type PiP task, + // then this is legacy-enter PiP. + return info.getChanges().size() == 1 + && TransitionUtil.isOpeningMode(pipChange.getMode()); + } + return false; } private boolean isRemovePipTransition(@NonNull TransitionInfo info) { @@ -951,6 +961,20 @@ public class PipTransition extends PipTransitionController implements initActivityPos.y); } } + + /** + * Sets the type of animation to run upon entering PiP. + * + * By default, {@link PipTransition} uses various signals from Transitions to figure out + * the animation type. But we should provide the ability to override this animation type to + * mixed handlers, for instance, as they can split up and modify incoming {@link TransitionInfo} + * to pass it onto multiple {@link Transitions.TransitionHandler}s. + */ + @Override + public void setEnterAnimationType(@AnimationType int type) { + mEnterAnimationType = type; + } + void cacheAndStartTransitionAnimator(@NonNull ValueAnimator animator) { mTransitionAnimator = animator; mTransitionAnimator.start(); 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 9e88a260ac44..99a89a6b884f 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 @@ -300,7 +300,7 @@ public class SplitScreenController implements SplitDragPolicy.Starter, mTaskOrganizer, mDisplayController, mDisplayImeController, mDisplayInsetsController, mTransitions, mTransactionPool, mIconProvider, mMainExecutor, mMainHandler, mRecentTasksOptional, mLaunchAdjacentController, - mWindowDecorViewModel, mSplitState, mDesktopTasksController); + mWindowDecorViewModel, mSplitState, mDesktopTasksController, mRootTDAOrganizer); } @Override @@ -441,7 +441,7 @@ public class SplitScreenController implements SplitDragPolicy.Starter, */ public void prepareExitSplitScreen(WindowContainerTransaction wct, @StageType int stageToTop, @ExitReason int reason) { - mStageCoordinator.prepareExitSplitScreen(stageToTop, wct); + mStageCoordinator.prepareExitSplitScreen(stageToTop, wct, reason); mStageCoordinator.clearSplitPairedInRecents(reason); } 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 37c93518998a..511e426cc681 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 @@ -130,6 +130,7 @@ import com.android.internal.policy.FoldLockSettingsObserver; import com.android.internal.protolog.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.R; +import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.ComponentUtils; import com.android.wm.shell.common.DisplayController; @@ -168,6 +169,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.Executor; @@ -218,6 +220,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private final SplitscreenEventLogger mLogger; private final ShellExecutor mMainExecutor; private final Handler mMainHandler; + private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer; // Cache live tile tasks while entering recents, evict them from stages in finish transaction // if user is opening another task(s). private final ArrayList<Integer> mPausingTasks = new ArrayList<>(); @@ -354,7 +357,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, Handler mainHandler, Optional<RecentTasksController> recentTasks, LaunchAdjacentController launchAdjacentController, Optional<WindowDecorViewModel> windowDecorViewModel, SplitState splitState, - Optional<DesktopTasksController> desktopTasksController) { + Optional<DesktopTasksController> desktopTasksController, + RootTaskDisplayAreaOrganizer rootTDAOrganizer) { mContext = context; mDisplayId = displayId; mSyncQueue = syncQueue; @@ -367,6 +371,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mWindowDecorViewModel = windowDecorViewModel; mSplitState = splitState; mDesktopTasksController = desktopTasksController; + mRootTDAOrganizer = rootTDAOrganizer; taskOrganizer.createRootTask(displayId, WINDOWING_MODE_FULLSCREEN, this /* listener */); @@ -425,7 +430,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, Handler mainHandler, Optional<RecentTasksController> recentTasks, LaunchAdjacentController launchAdjacentController, Optional<WindowDecorViewModel> windowDecorViewModel, SplitState splitState, - Optional<DesktopTasksController> desktopTasksController) { + Optional<DesktopTasksController> desktopTasksController, + RootTaskDisplayAreaOrganizer rootTDAOrganizer) { mContext = context; mDisplayId = displayId; mSyncQueue = syncQueue; @@ -447,6 +453,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mWindowDecorViewModel = windowDecorViewModel; mSplitState = splitState; mDesktopTasksController = desktopTasksController; + mRootTDAOrganizer = rootTDAOrganizer; mDisplayController.addDisplayWindowListener(this); transitions.addHandler(this); @@ -880,7 +887,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private void startSingleTask(int taskId, Bundle options, WindowContainerTransaction wct, RemoteTransition remoteTransition) { if (mMainStage.containsTask(taskId) || mSideStage.containsTask(taskId)) { - prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct); + prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct, EXIT_REASON_FULLSCREEN_REQUEST); } if (mRecentTasks.isPresent()) { mRecentTasks.get().removeSplitPair(taskId); @@ -1433,7 +1440,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // on top and lead to no visible change. clearSplitPairedInRecents(reason); final WindowContainerTransaction wct = new WindowContainerTransaction(); - prepareExitSplitScreen(mLastActiveStage, wct); + prepareExitSplitScreen(mLastActiveStage, wct, reason); mSplitTransitions.startDismissTransition(wct, this, mLastActiveStage, reason); setSplitsVisible(false); mBreakOnNextWake = false; @@ -1527,7 +1534,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (!isSplitActive()) return; final int stage = getStageOfTask(toTopTaskId); final WindowContainerTransaction wct = new WindowContainerTransaction(); - prepareExitSplitScreen(stage, wct); + prepareExitSplitScreen(stage, wct, exitReason); mSplitTransitions.startDismissTransition(wct, this, stage, exitReason); // reset stages to their default sides. setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, null); @@ -1646,7 +1653,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, * to be used when exiting split might be bundled with other window operations. */ void prepareExitSplitScreen(@StageType int stageToTop, - @NonNull WindowContainerTransaction wct) { + @NonNull WindowContainerTransaction wct, @ExitReason int exitReason) { if (!isSplitActive()) return; ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareExitSplitScreen: stageToTop=%s", stageTypeToString(stageToTop)); @@ -1657,6 +1664,26 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } else { mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE); } + + if (exitReason != EXIT_REASON_DESKTOP_MODE) { + StageTaskListener toTopStage = stageToTop == STAGE_TYPE_MAIN ? mMainStage : mSideStage; + if (enableFlexibleSplit()) { + toTopStage = mStageOrderOperator.getAllStages().stream() + .filter(stage -> stage.getId() == stageToTop) + .findFirst().orElse(null); + } + final DisplayAreaInfo tdaInfo = mRootTDAOrganizer.getDisplayAreaInfo(mDisplayId); + Objects.requireNonNull(tdaInfo); + final int displayWindowingMode = + tdaInfo.configuration.windowConfiguration.getWindowingMode(); + // In freeform-first env, we need to explicitly set the windowing mode when leaving + // the split-screen to be fullscreen. + final int targetWindowingMode = displayWindowingMode == WINDOWING_MODE_FREEFORM + ? WINDOWING_MODE_FULLSCREEN : WINDOWING_MODE_UNDEFINED; + toTopStage.doForAllChildTaskInfos(taskInfo -> { + wct.setWindowingMode(taskInfo.token, targetWindowingMode); + }); + } deactivateSplit(wct, stageToTop); mSplitState.exit(); } @@ -2331,7 +2358,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE; } final WindowContainerTransaction wct = new WindowContainerTransaction(); - prepareExitSplitScreen(stageType, wct); + prepareExitSplitScreen(stageType, wct, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); clearSplitPairedInRecents(EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); mSplitTransitions.startDismissTransition(wct, StageCoordinator.this, stageType, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); @@ -2363,10 +2390,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } final WindowContainerTransaction wct = new WindowContainerTransaction(); toTopStage.resetBounds(wct); - prepareExitSplitScreen(dismissTop, wct); + prepareExitSplitScreen(dismissTop, wct, EXIT_REASON_DRAG_DIVIDER); if (mRootTaskInfo != null) { wct.setDoNotPip(mRootTaskInfo.token); } + mSplitTransitions.startDismissTransition(wct, this, dismissTop, EXIT_REASON_DRAG_DIVIDER); } @@ -2801,7 +2829,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // The top should be the opposite side that is closing: int dismissTop = getStageType(stage) == STAGE_TYPE_MAIN ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN; - prepareExitSplitScreen(dismissTop, out); + prepareExitSplitScreen(dismissTop, out, EXIT_REASON_APP_FINISHED); mSplitTransitions.setDismissTransition(transition, dismissTop, EXIT_REASON_APP_FINISHED); } else if (isOpening && !mPausingTasks.isEmpty()) { @@ -2809,7 +2837,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // recents, which means to dismiss the split pair to this task. int dismissTop = getStageType(stage) == STAGE_TYPE_MAIN ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE; - prepareExitSplitScreen(dismissTop, out); + prepareExitSplitScreen(dismissTop, out, EXIT_REASON_APP_FINISHED); mSplitTransitions.setDismissTransition(transition, dismissTop, EXIT_REASON_APP_FINISHED); } else if (!isSplitScreenVisible() && isOpening) { @@ -2822,7 +2850,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // If the trigger task is in fullscreen and in split, exit split and place // task on top final int stageType = getStageOfTask(triggerTask.taskId); - prepareExitSplitScreen(stageType, out); + prepareExitSplitScreen(stageType, out, EXIT_REASON_FULLSCREEN_REQUEST); mSplitTransitions.setDismissTransition(transition, stageType, EXIT_REASON_FULLSCREEN_REQUEST); } @@ -2850,7 +2878,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (anyStageContainsSingleFullscreenTask) { // A splitting task is opening to fullscreen causes one side of the split empty, // so appends operations to exit split. - prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out); + prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out, + EXIT_REASON_FULLSCREEN_REQUEST); } } else if (type == TRANSIT_KEYGUARD_OCCLUDE && triggerTask.topActivity != null && isSplitScreenVisible()) { @@ -2858,7 +2887,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // stage and move it to the top. int top = triggerTask.topActivity.equals(mMainStage.mRootTaskInfo.topActivity) ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE; - prepareExitSplitScreen(top, out); + prepareExitSplitScreen(top, out, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP); mSplitTransitions.setDismissTransition(transition, top, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP); } @@ -2940,7 +2969,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, topStage = STAGE_TYPE_SIDE; } } - prepareExitSplitScreen(topStage, outWCT); + prepareExitSplitScreen(topStage, outWCT, EXIT_REASON_UNKNOWN); } } @@ -3127,7 +3156,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // If there is a fullscreen opening change, we should not bring stage to top. prepareExitSplitScreen( !record.mContainShowFullscreenChange && isSplitScreenVisible() - ? dismissTop : STAGE_TYPE_UNDEFINED, wct); + ? dismissTop : STAGE_TYPE_UNDEFINED, wct, EXIT_REASON_APP_FINISHED); mSplitTransitions.startDismissTransition(wct, this, dismissTop, EXIT_REASON_APP_FINISHED); // This can happen in some pathological cases. For example: @@ -3368,7 +3397,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, (sideChild != null ? STAGE_TYPE_SIDE : STAGE_TYPE_UNDEFINED); pendingEnter.cancel( (cancelWct, cancelT) -> { - prepareExitSplitScreen(dismissTop, cancelWct); + prepareExitSplitScreen(dismissTop, cancelWct, EXIT_REASON_UNKNOWN); logExit(EXIT_REASON_UNKNOWN); }); Log.w(TAG, splitFailureMessage("startPendingEnterAnimation", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 021f6595d984..194114db0169 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -379,6 +379,13 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener { } } + void doForAllChildTaskInfos(Consumer<ActivityManager.RunningTaskInfo> consumer) { + for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { + final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); + consumer.accept(taskInfo); + } + } + /** Collects all the current child tasks and prepares transaction to evict them to display. */ void evictAllChildren(WindowContainerTransaction wct) { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java index c5e158c6b452..d71b7a1183f4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java @@ -62,6 +62,7 @@ public class TvSplitScreenController extends SplitScreenController { private final Optional<RecentTasksController> mRecentTasksOptional; private final LaunchAdjacentController mLaunchAdjacentController; private final SplitState mSplitState; + private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer; private final Handler mMainHandler; private final SystemWindows mSystemWindows; @@ -109,6 +110,7 @@ public class TvSplitScreenController extends SplitScreenController { mMainHandler = mainHandler; mSystemWindows = systemWindows; + mRootTDAOrganizer = rootTDAOrganizer; } /** @@ -121,7 +123,8 @@ public class TvSplitScreenController extends SplitScreenController { mTaskOrganizer, mDisplayController, mDisplayImeController, mDisplayInsetsController, mTransitions, mTransactionPool, mIconProvider, mMainExecutor, mMainHandler, - mRecentTasksOptional, mLaunchAdjacentController, mSplitState, mSystemWindows); + mRecentTasksOptional, mLaunchAdjacentController, mSplitState, mSystemWindows, + mRootTDAOrganizer); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java index e1bf12fc6082..d7f1ced1b432 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java @@ -20,6 +20,7 @@ import android.content.Context; import android.os.Handler; import com.android.launcher3.icons.IconProvider; +import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; @@ -55,11 +56,11 @@ public class TvStageCoordinator extends StageCoordinator Optional<RecentTasksController> recentTasks, LaunchAdjacentController launchAdjacentController, SplitState splitState, - SystemWindows systemWindows) { + SystemWindows systemWindows, RootTaskDisplayAreaOrganizer rootTDAOrganizer) { super(context, displayId, syncQueue, taskOrganizer, displayController, displayImeController, displayInsetsController, transitions, transactionPool, iconProvider, mainExecutor, mainHandler, recentTasks, launchAdjacentController, - Optional.empty(), splitState, Optional.empty()); + Optional.empty(), splitState, Optional.empty(), rootTDAOrganizer); mTvSplitMenuController = new TvSplitMenuController(context, this, systemWindows, mainHandler); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java index 2133275cde61..30ffdac5cbba 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java @@ -21,7 +21,7 @@ import static android.view.WindowManager.TRANSIT_PIP; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; -import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA; +import static com.android.wm.shell.pip.PipTransitionController.ANIM_TYPE_ALPHA; import static com.android.wm.shell.shared.TransitionUtil.isOpeningMode; import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; @@ -148,6 +148,7 @@ public class MixedTransitionHelper { } } + pipHandler.setEnterAnimationType(ANIM_TYPE_ALPHA); if (PipUtils.isPip2ExperimentEnabled()) { TransitionInfo pipInfo = subCopy(info, TRANSIT_PIP, false /* withChanges */); pipInfo.getChanges().add(pipChange); @@ -157,7 +158,6 @@ public class MixedTransitionHelper { pipHandler.startAnimation(mixed.mTransition, pipInfo, startTransaction, finishTransaction, finishCB); } else { - pipHandler.setEnterAnimationType(ANIM_TYPE_ALPHA); pipHandler.startEnterAnimation(pipChange, startTransaction, finishTransaction, finishCB); } 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 51b0291cab91..fad1c9f848ea 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 @@ -751,7 +751,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, // been added, so they must be added here decoration.addCaptionInset(wct); mDesktopTasksController.moveTaskToDesktop(taskId, wct, source, - /* remoteTransition= */ null); + /* remoteTransition= */ null, /* moveToDesktopCallback */ null); decoration.closeHandleMenu(); if (source == DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON) { 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 39a989ce7c7f..fe9bdb027d18 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 @@ -423,6 +423,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } @Override + void onExclusionRegionChanged(@NonNull Region exclusionRegion) { + if (Flags.appHandleNoRelayoutOnExclusionChange() && isAppHandle(mWindowDecorViewHolder)) { + // Avoid unnecessary relayouts for app handle. See b/383672263 + return; + } + relayout(mTaskInfo, mHasGlobalFocus, exclusionRegion); + } + + @Override void relayout(ActivityManager.RunningTaskInfo taskInfo, boolean hasGlobalFocus, @NonNull Region displayExclusionRegion) { final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get(); @@ -533,6 +542,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin if (appHeader != null) { appHeader.setAppName(name); appHeader.setAppIcon(icon); + if (canEnterDesktopMode(mContext) && isEducationEnabled()) { + notifyCaptionStateChanged(); + } } }); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/WindowDecorTaskResourceLoader.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/WindowDecorTaskResourceLoader.kt index d87da092cccf..1bc48f89ea6d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/WindowDecorTaskResourceLoader.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/WindowDecorTaskResourceLoader.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.windowdecor.common import android.annotation.DimenRes -import android.app.ActivityManager import android.app.ActivityManager.RunningTaskInfo import android.content.Context import android.content.pm.ActivityInfo @@ -29,6 +28,7 @@ import com.android.launcher3.icons.BaseIconFactory import com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT import com.android.launcher3.icons.IconProvider import com.android.wm.shell.R +import com.android.wm.shell.common.UserProfileContexts import com.android.wm.shell.shared.annotations.ShellBackgroundThread import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController @@ -41,10 +41,10 @@ import java.util.concurrent.ConcurrentHashMap * A utility and cache for window decoration UI resources. */ class WindowDecorTaskResourceLoader( - private val context: Context, shellInit: ShellInit, private val shellController: ShellController, private val shellCommandHandler: ShellCommandHandler, + private val userProfilesContexts: UserProfileContexts, private val iconProvider: IconProvider, private val headerIconFactory: BaseIconFactory, private val veilIconFactory: BaseIconFactory, @@ -54,11 +54,12 @@ class WindowDecorTaskResourceLoader( shellInit: ShellInit, shellController: ShellController, shellCommandHandler: ShellCommandHandler, + userProfileContexts: UserProfileContexts, ) : this( - context, shellInit, shellController, shellCommandHandler, + userProfileContexts, IconProvider(context), headerIconFactory = context.createIconFactory(R.dimen.desktop_mode_caption_icon_radius), veilIconFactory = context.createIconFactory(R.dimen.desktop_mode_resize_veil_icon_size), @@ -79,9 +80,6 @@ class WindowDecorTaskResourceLoader( */ private val existingTasks = mutableSetOf<Int>() - @VisibleForTesting - lateinit var currentUserContext: Context - init { shellInit.addInitCallback(this::onInit, this) } @@ -90,14 +88,10 @@ class WindowDecorTaskResourceLoader( shellCommandHandler.addDumpCallback(this::dump, this) shellController.addUserChangeListener(object : UserChangeListener { override fun onUserChanged(newUserId: Int, userContext: Context) { - currentUserContext = userContext // No need to hold on to resources for tasks of another profile. taskToResourceCache.clear() } }) - currentUserContext = context.createContextAsUser( - UserHandle.of(ActivityManager.getCurrentUser()), /* flags= */ 0 - ) } /** Returns the user readable name for this task. */ @@ -158,15 +152,20 @@ class WindowDecorTaskResourceLoader( private fun loadAppResources(taskInfo: RunningTaskInfo): AppResources { Trace.beginSection("$TAG#loadAppResources") - val pm = currentUserContext.packageManager - val activityInfo = getActivityInfo(taskInfo, pm) - val appName = pm.getApplicationLabel(activityInfo.applicationInfo) - val appIconDrawable = iconProvider.getIcon(activityInfo) - val badgedAppIconDrawable = pm.getUserBadgedIcon(appIconDrawable, taskInfo.userHandle()) - val appIcon = headerIconFactory.createIconBitmap(badgedAppIconDrawable, /* scale= */ 1f) - val veilIcon = veilIconFactory.createScaledBitmap(appIconDrawable, MODE_DEFAULT) - Trace.endSection() - return AppResources(appName = appName, appIcon = appIcon, veilIcon = veilIcon) + try { + val pm = checkNotNull(userProfilesContexts[taskInfo.userId]?.packageManager) { + "Could not get context for user ${taskInfo.userId}" + } + val activityInfo = getActivityInfo(taskInfo, pm) + val appName = pm.getApplicationLabel(activityInfo.applicationInfo) + val appIconDrawable = iconProvider.getIcon(activityInfo) + val badgedAppIconDrawable = pm.getUserBadgedIcon(appIconDrawable, taskInfo.userHandle()) + val appIcon = headerIconFactory.createIconBitmap(badgedAppIconDrawable, /* scale= */ 1f) + val veilIcon = veilIconFactory.createScaledBitmap(appIconDrawable, MODE_DEFAULT) + return AppResources(appName = appName, appIcon = appIcon, veilIcon = veilIcon) + } finally { + Trace.endSection() + } } private fun getActivityInfo(taskInfo: RunningTaskInfo, pm: PackageManager): ActivityInfo { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt index dc4fa3788778..79c5eff01b4c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt @@ -329,11 +329,6 @@ class AppHeaderViewHolder( } fun runOnAppChipGlobalLayout(runnable: () -> Unit) { - if (openMenuButton.isAttachedToWindow) { - // App chip is already inflated. - runnable() - return - } // Wait for app chip to be inflated before notifying repository. openMenuButton.viewTreeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/UserProfileContextsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/UserProfileContextsTest.kt new file mode 100644 index 000000000000..ef0b8ab14c81 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/UserProfileContextsTest.kt @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.common + +import android.app.ActivityManager +import android.content.Context +import android.content.pm.UserInfo +import android.os.UserHandle +import android.os.UserManager +import android.testing.AndroidTestingRunner +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestShellExecutor +import com.android.wm.shell.sysui.ShellController +import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.sysui.UserChangeListener +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.anyInt +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +/** + * Tests for [UserProfileContexts]. + */ +@RunWith(AndroidTestingRunner::class) +class UserProfileContextsTest : ShellTestCase() { + + private val testExecutor = TestShellExecutor() + private val shellInit = ShellInit(testExecutor) + private val activityManager = mock<ActivityManager>() + private val userManager = mock<UserManager>() + private val shellController = mock<ShellController>() + private val baseContext = mock<Context>() + + private lateinit var userProfilesContexts: UserProfileContexts + + @Before + fun setUp() { + doReturn(activityManager) + .whenever(baseContext) + .getSystemService(eq(ActivityManager::class.java)) + doReturn(userManager).whenever(baseContext).getSystemService(eq(UserManager::class.java)) + doAnswer { invocation -> + val userHandle = invocation.getArgument<UserHandle>(0) + createContextForUser(userHandle.identifier) + } + .whenever(baseContext) + .createContextAsUser(any<UserHandle>(), anyInt()) + // Define users and profiles + val currentUser = ActivityManager.getCurrentUser() + whenever(userManager.getProfiles(eq(currentUser))) + .thenReturn( + listOf(UserInfo(currentUser, "Current", 0), UserInfo(MAIN_PROFILE, "Work", 0)) + ) + whenever(userManager.getProfiles(eq(SECOND_USER))).thenReturn(SECOND_PROFILES) + userProfilesContexts = UserProfileContexts(baseContext, shellController, shellInit) + shellInit.init() + } + + @Test + fun onInit_registerUserChangeAndInit() { + val currentUser = ActivityManager.getCurrentUser() + + verify(shellController, times(1)).addUserChangeListener(any()) + assertThat(userProfilesContexts.userContext.userId).isEqualTo(currentUser) + assertThat(userProfilesContexts[currentUser]?.userId).isEqualTo(currentUser) + assertThat(userProfilesContexts[MAIN_PROFILE]?.userId).isEqualTo(MAIN_PROFILE) + assertThat(userProfilesContexts[SECOND_USER]).isNull() + } + + @Test + fun onUserChanged_updateUserContext() { + val userChangeListener = retrieveUserChangeListener() + val newUserContext = createContextForUser(SECOND_USER) + + userChangeListener.onUserChanged(SECOND_USER, newUserContext) + + assertThat(userProfilesContexts.userContext).isEqualTo(newUserContext) + assertThat(userProfilesContexts[SECOND_USER]).isEqualTo(newUserContext) + } + + @Test + fun onUserProfilesChanged_updateAllContexts() { + val userChangeListener = retrieveUserChangeListener() + val newUserContext = createContextForUser(SECOND_USER) + userChangeListener.onUserChanged(SECOND_USER, newUserContext) + + userChangeListener.onUserProfilesChanged(SECOND_PROFILES) + + assertThat(userProfilesContexts.userContext).isEqualTo(newUserContext) + assertThat(userProfilesContexts[SECOND_USER]).isEqualTo(newUserContext) + assertThat(userProfilesContexts[SECOND_PROFILE]?.userId).isEqualTo(SECOND_PROFILE) + assertThat(userProfilesContexts[SECOND_PROFILE_2]?.userId).isEqualTo(SECOND_PROFILE_2) + } + + @Test + fun onUserProfilesChanged_keepOnlyNewProfiles() { + val userChangeListener = retrieveUserChangeListener() + val newUserContext = createContextForUser(SECOND_USER) + userChangeListener.onUserChanged(SECOND_USER, newUserContext) + userChangeListener.onUserProfilesChanged(SECOND_PROFILES) + val newProfiles = listOf( + UserInfo(SECOND_USER, "Second", 0), + UserInfo(SECOND_PROFILE, "Second Profile", 0), + UserInfo(MAIN_PROFILE, "Main profile", 0), + ) + + userChangeListener.onUserProfilesChanged(newProfiles) + + assertThat(userProfilesContexts[SECOND_PROFILE_2]).isNull() + assertThat(userProfilesContexts[MAIN_PROFILE]?.userId).isEqualTo(MAIN_PROFILE) + assertThat(userProfilesContexts[SECOND_USER]?.userId).isEqualTo(SECOND_USER) + assertThat(userProfilesContexts[SECOND_PROFILE]?.userId).isEqualTo(SECOND_PROFILE) + } + + private fun retrieveUserChangeListener(): UserChangeListener { + val captor = argumentCaptor<UserChangeListener>() + + verify(shellController, times(1)).addUserChangeListener(captor.capture()) + + return captor.firstValue + } + + private fun createContextForUser(userId: Int): Context { + val newContext = mock<Context>() + whenever(newContext.userId).thenReturn(userId) + return newContext + } + + private companion object { + const val SECOND_USER = 3 + const val MAIN_PROFILE = 11 + const val SECOND_PROFILE = 15 + const val SECOND_PROFILE_2 = 17 + + val SECOND_PROFILES = + listOf( + UserInfo(SECOND_USER, "Second", 0), + UserInfo(SECOND_PROFILE, "Second Profile", 0), + UserInfo(SECOND_PROFILE_2, "Second Profile 2", 0), + ) + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt index ecad5217b87f..957fdf995776 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt @@ -183,6 +183,8 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Test fun handleActivityOrientationChange_resizeable_doNothing() { + userRepositories.current.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + userRepositories.current.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val task = setUpFreeformTask() taskStackListener.onActivityRequestedOrientationChanged( @@ -195,6 +197,8 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Test fun handleActivityOrientationChange_nonResizeableFullscreen_doNothing() { + userRepositories.current.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + userRepositories.current.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val task = createFullscreenTask() task.isResizeable = false val activityInfo = ActivityInfo() @@ -214,6 +218,8 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Test fun handleActivityOrientationChange_nonResizeablePortrait_requestSameOrientation_doNothing() { + userRepositories.current.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + userRepositories.current.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val task = setUpFreeformTask(isResizeable = false) val newTask = setUpFreeformTask( @@ -228,6 +234,8 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Test fun handleActivityOrientationChange_notInDesktopMode_doNothing() { + userRepositories.current.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + userRepositories.current.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val task = setUpFreeformTask(isResizeable = false) userRepositories.current.updateTask(task.displayId, task.taskId, isVisible = false) @@ -241,6 +249,8 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Test fun handleActivityOrientationChange_nonResizeablePortrait_respectLandscapeRequest() { + userRepositories.current.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + userRepositories.current.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val task = setUpFreeformTask(isResizeable = false) val oldBounds = task.configuration.windowConfiguration.bounds val newTask = @@ -263,6 +273,8 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Test fun handleActivityOrientationChange_nonResizeableLandscape_respectPortraitRequest() { + userRepositories.current.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + userRepositories.current.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val oldBounds = Rect(0, 0, 500, 200) val task = setUpFreeformTask( diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt index 6a3717427e93..5d8d5a716504 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt @@ -20,6 +20,8 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.content.ContentResolver import android.os.Binder +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule import android.provider.Settings import android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS import android.testing.AndroidTestingRunner @@ -29,20 +31,25 @@ import android.view.WindowManager.TRANSIT_CHANGE import android.window.DisplayAreaInfo import android.window.WindowContainerTransaction import androidx.test.filters.SmallTest +import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.ExtendedMockito.never +import com.android.dx.mockito.inline.extended.StaticMockitoSession +import com.android.window.flags.Flags import com.android.wm.shell.MockToken import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions import com.google.common.truth.Truth.assertThat +import org.junit.After import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.isNull import org.mockito.Mock import org.mockito.Mockito.anyInt @@ -53,6 +60,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.eq import org.mockito.kotlin.whenever +import org.mockito.quality.Strictness /** * Test class for [DesktopDisplayEventHandler] @@ -63,18 +71,33 @@ import org.mockito.kotlin.whenever @RunWith(AndroidTestingRunner::class) class DesktopDisplayEventHandlerTest : ShellTestCase() { + @JvmField @Rule val setFlagsRule = SetFlagsRule() + @Mock lateinit var testExecutor: ShellExecutor @Mock lateinit var transitions: Transitions @Mock lateinit var displayController: DisplayController @Mock lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer @Mock private lateinit var mockWindowManager: IWindowManager + @Mock private lateinit var mockDesktopUserRepositories: DesktopUserRepositories + @Mock private lateinit var mockDesktopRepository: DesktopRepository + @Mock private lateinit var mockDesktopTasksController: DesktopTasksController + private lateinit var mockitoSession: StaticMockitoSession private lateinit var shellInit: ShellInit private lateinit var handler: DesktopDisplayEventHandler + private val onDisplaysChangedListenerCaptor = argumentCaptor<OnDisplaysChangedListener>() + @Before fun setUp() { + mockitoSession = + mockitoSession() + .strictness(Strictness.LENIENT) + .spyStatic(DesktopModeStatus::class.java) + .startMocking() + shellInit = spy(ShellInit(testExecutor)) + whenever(mockDesktopUserRepositories.current).thenReturn(mockDesktopRepository) whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() } val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(tda) @@ -86,8 +109,17 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { displayController, rootTaskDisplayAreaOrganizer, mockWindowManager, + mockDesktopUserRepositories, + mockDesktopTasksController, ) shellInit.init() + verify(displayController) + .addDisplayWindowListener(onDisplaysChangedListenerCaptor.capture()) + } + + @After + fun tearDown() { + mockitoSession.finishMocking() } private fun testDisplayWindowingModeSwitch( @@ -96,8 +128,6 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { expectTransition: Boolean, ) { val externalDisplayId = 100 - val captor = ArgumentCaptor.forClass(OnDisplaysChangedListener::class.java) - verify(displayController).addDisplayWindowListener(captor.capture()) val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!! tda.configuration.windowConfiguration.windowingMode = defaultWindowingMode whenever(mockWindowManager.getWindowingMode(anyInt())).thenAnswer { defaultWindowingMode } @@ -111,12 +141,12 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { // The external display connected. whenever(rootTaskDisplayAreaOrganizer.getDisplayIds()) .thenReturn(intArrayOf(DEFAULT_DISPLAY, externalDisplayId)) - captor.value.onDisplayAdded(externalDisplayId) + onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(externalDisplayId) tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM // The external display disconnected. whenever(rootTaskDisplayAreaOrganizer.getDisplayIds()) .thenReturn(intArrayOf(DEFAULT_DISPLAY)) - captor.value.onDisplayRemoved(externalDisplayId) + onDisplaysChangedListenerCaptor.lastValue.onDisplayRemoved(externalDisplayId) if (expectTransition) { val arg = argumentCaptor<WindowContainerTransaction>() @@ -159,6 +189,44 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { ) } + @Test + fun testDisplayAdded_supportsDesks_createsDesk() { + whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(true) + + onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(DEFAULT_DISPLAY) + + verify(mockDesktopTasksController).createDesk(DEFAULT_DISPLAY) + } + + @Test + fun testDisplayAdded_cannotEnterDesktopMode_doesNotCreateDesk() { + whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(false) + + onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(DEFAULT_DISPLAY) + + verify(mockDesktopTasksController, never()).createDesk(DEFAULT_DISPLAY) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun testDeskRemoved_noDesksRemain_createsDesk() { + whenever(mockDesktopRepository.getNumberOfDesks(DEFAULT_DISPLAY)).thenReturn(0) + + handler.onDeskRemoved(DEFAULT_DISPLAY, deskId = 1) + + verify(mockDesktopTasksController).createDesk(DEFAULT_DISPLAY) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun testDeskRemoved_desksRemain_doesNotCreateDesk() { + whenever(mockDesktopRepository.getNumberOfDesks(DEFAULT_DISPLAY)).thenReturn(1) + + handler.onDeskRemoved(DEFAULT_DISPLAY, deskId = 1) + + verify(mockDesktopTasksController, never()).createDesk(DEFAULT_DISPLAY) + } + private class ExtendedDisplaySettingsSession( private val contentResolver: ContentResolver, private val overrideValue: Int, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt index 8d73f3f59afd..5736793cd6a9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt @@ -18,12 +18,13 @@ package com.android.wm.shell.desktopmode import android.graphics.Rect import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.FlagsParameterization import android.platform.test.flag.junit.SetFlagsRule -import android.testing.AndroidTestingRunner import android.util.ArraySet import android.view.Display.DEFAULT_DISPLAY import android.view.Display.INVALID_DISPLAY import androidx.test.filters.SmallTest +import com.android.window.flags.Flags import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP import com.android.wm.shell.ShellTestCase @@ -56,6 +57,8 @@ import org.mockito.kotlin.never import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters /** * Tests for [@link DesktopRepository]. @@ -63,11 +66,11 @@ import org.mockito.kotlin.whenever * Build/Install/Run: atest WMShellUnitTests:DesktopRepositoryTest */ @SmallTest -@RunWith(AndroidTestingRunner::class) +@RunWith(ParameterizedAndroidJunit4::class) @ExperimentalCoroutinesApi -class DesktopRepositoryTest : ShellTestCase() { +class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() { - @JvmField @Rule val setFlagsRule = SetFlagsRule() + @JvmField @Rule val setFlagsRule = SetFlagsRule(flags) private lateinit var repo: DesktopRepository private lateinit var shellInit: ShellInit @@ -86,6 +89,8 @@ class DesktopRepositoryTest : ShellTestCase() { whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }) .thenReturn(Desktop.getDefaultInstance()) shellInit.init() + repo.addDesk(displayId = DEFAULT_DISPLAY, deskId = DEFAULT_DESKTOP_ID) + repo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = DEFAULT_DESKTOP_ID) } @After @@ -137,6 +142,7 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun addTask_multipleDisplays_notifiesCorrectListener() { + repo.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val listener = TestListener() repo.addActiveTaskListener(listener) @@ -150,6 +156,7 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun addTask_multipleDisplays_moveToAnotherDisplay() { + repo.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) repo.addTask(DEFAULT_DISPLAY, taskId = 1, isVisible = true) repo.addTask(SECOND_DISPLAY, taskId = 1, isVisible = true) assertThat(repo.getFreeformTasksInZOrder(DEFAULT_DISPLAY)).isEmpty() @@ -310,19 +317,21 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun isOnlyVisibleNonClosingTask_multipleDisplays() { + repo.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) + repo.setActiveDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) repo.updateTask(DEFAULT_DISPLAY, taskId = 1, isVisible = true) repo.updateTask(DEFAULT_DISPLAY, taskId = 2, isVisible = true) repo.updateTask(SECOND_DISPLAY, taskId = 3, isVisible = true) // Not the only task on DEFAULT_DISPLAY assertThat(repo.isVisibleTask(1)).isTrue() - assertThat(repo.isOnlyVisibleNonClosingTask(1)).isFalse() + assertThat(repo.isOnlyVisibleNonClosingTask(1, DEFAULT_DISPLAY)).isFalse() // Not the only task on DEFAULT_DISPLAY assertThat(repo.isVisibleTask(2)).isTrue() - assertThat(repo.isOnlyVisibleNonClosingTask(2)).isFalse() + assertThat(repo.isOnlyVisibleNonClosingTask(2, DEFAULT_DISPLAY)).isFalse() // The only visible task on SECOND_DISPLAY assertThat(repo.isVisibleTask(3)).isTrue() - assertThat(repo.isOnlyVisibleNonClosingTask(3)).isTrue() + assertThat(repo.isOnlyVisibleNonClosingTask(3, SECOND_DISPLAY)).isTrue() // Not a visible task assertThat(repo.isVisibleTask(99)).isFalse() assertThat(repo.isOnlyVisibleNonClosingTask(99)).isFalse() @@ -343,6 +352,7 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun addListener_tasksOnDifferentDisplay_doesNotNotify() { + repo.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) repo.updateTask(SECOND_DISPLAY, taskId = 1, isVisible = true) val listener = TestVisibilityListener() val executor = TestShellExecutor() @@ -351,7 +361,7 @@ class DesktopRepositoryTest : ShellTestCase() { assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(0) // One call as adding listener notifies it - assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(0) + assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(1) } @Test @@ -365,11 +375,14 @@ class DesktopRepositoryTest : ShellTestCase() { executor.flushAll() assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(2) - assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(2) + // 1 from registration, 2 for the updates. + assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(3) } @Test fun updateTask_visibleTask_addVisibleTaskNotifiesListenerForThatDisplay() { + repo.addDesk(displayId = 1, deskId = 1) + repo.setActiveDesk(displayId = 1, deskId = 1) val listener = TestVisibilityListener() val executor = TestShellExecutor() repo.addVisibleTasksListener(listener, executor) @@ -378,22 +391,27 @@ class DesktopRepositoryTest : ShellTestCase() { executor.flushAll() assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(1) - assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(1) + // 1 for the registration, 1 for the update. + assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(2) assertThat(listener.visibleTasksCountOnSecondaryDisplay).isEqualTo(0) - assertThat(listener.visibleChangesOnSecondaryDisplay).isEqualTo(0) + // 1 for the registration. + assertThat(listener.visibleChangesOnSecondaryDisplay).isEqualTo(1) repo.updateTask(displayId = 1, taskId = 2, isVisible = true) executor.flushAll() // Listener for secondary display is notified assertThat(listener.visibleTasksCountOnSecondaryDisplay).isEqualTo(1) - assertThat(listener.visibleChangesOnSecondaryDisplay).isEqualTo(1) + // 1 for the registration, 1 for the update. + assertThat(listener.visibleChangesOnSecondaryDisplay).isEqualTo(2) // No changes to listener for default display - assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(1) + assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(2) } @Test fun updateTask_taskOnDefaultBecomesVisibleOnSecondDisplay_listenersNotified() { + repo.addDesk(displayId = 1, deskId = 1) + repo.setActiveDesk(displayId = 1, deskId = 1) val listener = TestVisibilityListener() val executor = TestShellExecutor() repo.addVisibleTasksListener(listener, executor) @@ -406,14 +424,15 @@ class DesktopRepositoryTest : ShellTestCase() { repo.updateTask(displayId = 1, taskId = 1, isVisible = true) executor.flushAll() - // Default display should have 2 calls - // 1 - visible task added - // 2 - visible task removed - assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(2) + // Default display should have 3 calls + // 1 - listener registered + // 2 - visible task added + // 3 - visible task removed + assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(3) assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(0) - // Secondary display should have 1 call for visible task added - assertThat(listener.visibleChangesOnSecondaryDisplay).isEqualTo(1) + // Secondary display should have 2 calls for registration + visible task added + assertThat(listener.visibleChangesOnSecondaryDisplay).isEqualTo(2) assertThat(listener.visibleTasksCountOnSecondaryDisplay).isEqualTo(1) } @@ -431,13 +450,13 @@ class DesktopRepositoryTest : ShellTestCase() { repo.updateTask(DEFAULT_DISPLAY, taskId = 1, isVisible = false) executor.flushAll() - assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(3) + assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(4) repo.updateTask(DEFAULT_DISPLAY, taskId = 2, isVisible = false) executor.flushAll() assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(0) - assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(4) + assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(5) } /** @@ -458,7 +477,8 @@ class DesktopRepositoryTest : ShellTestCase() { repo.updateTask(INVALID_DISPLAY, taskId = 1, isVisible = false) executor.flushAll() - assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(3) + // 1 from registering, 1x3 for each update including the one to the invalid display. + assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(4) assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(1) } @@ -497,6 +517,8 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun getVisibleTaskCount_multipleDisplays_returnsCorrectCount() { + repo.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) + repo.setActiveDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) assertThat(repo.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0) assertThat(repo.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(0) @@ -674,8 +696,6 @@ class DesktopRepositoryTest : ShellTestCase() { repo.removeTask(INVALID_DISPLAY, taskId = 1) - val invalidDisplayTasks = repo.getFreeformTasksInZOrder(INVALID_DISPLAY) - assertThat(invalidDisplayTasks).isEmpty() val validDisplayTasks = repo.getFreeformTasksInZOrder(DEFAULT_DISPLAY) assertThat(validDisplayTasks).isEmpty() } @@ -746,6 +766,7 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun removeTask_validDisplay_differentDisplay_doesNotRemovesTask() { + repo.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) repo.addTask(DEFAULT_DISPLAY, taskId = 1, isVisible = true) repo.removeTask(SECOND_DISPLAY, taskId = 1) @@ -758,6 +779,7 @@ class DesktopRepositoryTest : ShellTestCase() { @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE) fun removeTask_validDisplayButDifferentDisplay_persistenceEnabled_doesNotRemoveTask() { runTest(StandardTestDispatcher()) { + repo.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) repo.addTask(DEFAULT_DISPLAY, taskId = 1, isVisible = true) repo.removeTask(SECOND_DISPLAY, taskId = 1) @@ -784,10 +806,10 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun removeTask_removesTaskBoundsBeforeMaximize() { val taskId = 1 - repo.addTask(THIRD_DISPLAY, taskId, isVisible = true) + repo.addTask(DEFAULT_DISPLAY, taskId, isVisible = true) repo.saveBoundsBeforeMaximize(taskId, Rect(0, 0, 200, 200)) - repo.removeTask(THIRD_DISPLAY, taskId) + repo.removeTask(DEFAULT_DISPLAY, taskId) assertThat(repo.removeBoundsBeforeMaximize(taskId)).isNull() } @@ -795,16 +817,17 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun removeTask_removesTaskBoundsBeforeImmersive() { val taskId = 1 - repo.addTask(THIRD_DISPLAY, taskId, isVisible = true) + repo.addTask(DEFAULT_DISPLAY, taskId, isVisible = true) repo.saveBoundsBeforeFullImmersive(taskId, Rect(0, 0, 200, 200)) - repo.removeTask(THIRD_DISPLAY, taskId) + repo.removeTask(DEFAULT_DISPLAY, taskId) assertThat(repo.removeBoundsBeforeFullImmersive(taskId)).isNull() } @Test fun removeTask_removesActiveTask() { + repo.addDesk(THIRD_DISPLAY, THIRD_DISPLAY) val taskId = 1 val listener = TestListener() repo.addActiveTaskListener(listener) @@ -829,6 +852,7 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun removeTask_updatesTaskVisibility() { + repo.addDesk(displayId = THIRD_DISPLAY, deskId = THIRD_DISPLAY) val taskId = 1 repo.addTask(DEFAULT_DISPLAY, taskId, isVisible = true) @@ -930,8 +954,8 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun updateTask_minimizedTaskBecomesVisible_unminimizesTask() { - repo.minimizeTask(displayId = 10, taskId = 2) - repo.updateTask(displayId = 10, taskId = 2, isVisible = true) + repo.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = 2) + repo.updateTask(displayId = DEFAULT_DISPLAY, taskId = 2, isVisible = true) val isMinimizedTask = repo.isMinimizedTask(taskId = 2) @@ -1003,34 +1027,34 @@ class DesktopRepositoryTest : ShellTestCase() { fun setTaskInFullImmersiveState_savedAsInImmersiveState() { assertThat(repo.isTaskInFullImmersiveState(taskId = 1)).isFalse() - repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID, taskId = 1, immersive = true) + repo.setTaskInFullImmersiveState(DEFAULT_DISPLAY, taskId = 1, immersive = true) assertThat(repo.isTaskInFullImmersiveState(taskId = 1)).isTrue() } @Test fun removeTaskInFullImmersiveState_removedAsInImmersiveState() { - repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID, taskId = 1, immersive = true) + repo.setTaskInFullImmersiveState(DEFAULT_DISPLAY, taskId = 1, immersive = true) assertThat(repo.isTaskInFullImmersiveState(taskId = 1)).isTrue() - repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID, taskId = 1, immersive = false) + repo.setTaskInFullImmersiveState(DEFAULT_DISPLAY, taskId = 1, immersive = false) assertThat(repo.isTaskInFullImmersiveState(taskId = 1)).isFalse() } @Test fun removeTaskInFullImmersiveState_otherWasImmersive_otherRemainsImmersive() { - repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID, taskId = 1, immersive = true) + repo.setTaskInFullImmersiveState(DEFAULT_DISPLAY, taskId = 1, immersive = true) - repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID, taskId = 2, immersive = false) + repo.setTaskInFullImmersiveState(DEFAULT_DISPLAY, taskId = 2, immersive = false) assertThat(repo.isTaskInFullImmersiveState(taskId = 1)).isTrue() } @Test fun setTaskInFullImmersiveState_sameDisplay_overridesExistingFullImmersiveTask() { - repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID, taskId = 1, immersive = true) - repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID, taskId = 2, immersive = true) + repo.setTaskInFullImmersiveState(DEFAULT_DISPLAY, taskId = 1, immersive = true) + repo.setTaskInFullImmersiveState(DEFAULT_DISPLAY, taskId = 2, immersive = true) assertThat(repo.isTaskInFullImmersiveState(taskId = 1)).isFalse() assertThat(repo.isTaskInFullImmersiveState(taskId = 2)).isTrue() @@ -1038,8 +1062,10 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun setTaskInFullImmersiveState_differentDisplay_bothAreImmersive() { - repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID, taskId = 1, immersive = true) - repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID + 1, taskId = 2, immersive = true) + repo.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) + repo.setActiveDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) + repo.setTaskInFullImmersiveState(DEFAULT_DISPLAY, taskId = 1, immersive = true) + repo.setTaskInFullImmersiveState(SECOND_DISPLAY, taskId = 2, immersive = true) assertThat(repo.isTaskInFullImmersiveState(taskId = 1)).isTrue() assertThat(repo.isTaskInFullImmersiveState(taskId = 2)).isTrue() @@ -1061,11 +1087,13 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun getTaskInFullImmersiveState_byDisplay() { + repo.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) + repo.setActiveDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID, taskId = 1, immersive = true) - repo.setTaskInFullImmersiveState(DEFAULT_DESKTOP_ID + 1, taskId = 2, immersive = true) + repo.setTaskInFullImmersiveState(SECOND_DISPLAY, taskId = 2, immersive = true) assertThat(repo.getTaskInFullImmersiveState(DEFAULT_DESKTOP_ID)).isEqualTo(1) - assertThat(repo.getTaskInFullImmersiveState(DEFAULT_DESKTOP_ID + 1)).isEqualTo(2) + assertThat(repo.getTaskInFullImmersiveState(SECOND_DISPLAY)).isEqualTo(2) } @Test @@ -1089,11 +1117,13 @@ class DesktopRepositoryTest : ShellTestCase() { @Test fun setTaskInPip_multipleDisplays_bothAreInPip() { + repo.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) + repo.setActiveDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) repo.setTaskInPip(DEFAULT_DESKTOP_ID, taskId = 1, enterPip = true) - repo.setTaskInPip(DEFAULT_DESKTOP_ID + 1, taskId = 2, enterPip = true) + repo.setTaskInPip(SECOND_DISPLAY, taskId = 2, enterPip = true) assertThat(repo.isTaskMinimizedPipInDisplay(DEFAULT_DESKTOP_ID, taskId = 1)).isTrue() - assertThat(repo.isTaskMinimizedPipInDisplay(DEFAULT_DESKTOP_ID + 1, taskId = 2)).isTrue() + assertThat(repo.isTaskMinimizedPipInDisplay(SECOND_DISPLAY, taskId = 2)).isTrue() } @Test @@ -1169,5 +1199,10 @@ class DesktopRepositoryTest : ShellTestCase() { const val THIRD_DISPLAY = 345 private const val DEFAULT_USER_ID = 1000 private const val DEFAULT_DESKTOP_ID = 0 + + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> = + FlagsParameterization.allCombinationsOf(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt index c7c0dfc5be6d..12c7ff61399f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt @@ -144,6 +144,16 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { } @Test + fun onTaskMovingToFront_freeformTaskOutsideDesktop_addsTaskToRepo() { + val task = createFullscreenTask().apply { isVisible = true } + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) + + desktopTaskChangeListener.onTaskMovingToFront(task) + + verify(desktopUserRepositories.current).addTask(task.displayId, task.taskId, task.isVisible) + } + + @Test @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) fun onTaskClosing_backNavEnabled_nonClosingTask_minimizesTaskInRepo() { val task = createFreeformTask().apply { isVisible = true } 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 db19017ef87a..46222674ff05 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 @@ -48,8 +48,8 @@ import android.os.IBinder import android.os.UserManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.FlagsParameterization import android.platform.test.flag.junit.SetFlagsRule -import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY import android.view.DragEvent import android.view.Gravity @@ -100,6 +100,7 @@ import com.android.wm.shell.common.DisplayLayout import com.android.wm.shell.common.MultiInstanceHelper import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.SyncTransactionQueue +import com.android.wm.shell.common.UserProfileContexts import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitResult import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason @@ -117,6 +118,7 @@ import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCR import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider import com.android.wm.shell.desktopmode.minimize.DesktopWindowLimitRemoteHandler +import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer import com.android.wm.shell.desktopmode.persistence.Desktop import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer @@ -184,6 +186,8 @@ import org.mockito.kotlin.capture import org.mockito.kotlin.eq import org.mockito.kotlin.whenever import org.mockito.quality.Strictness +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters /** * Test class for {@link DesktopTasksController} @@ -191,12 +195,12 @@ import org.mockito.quality.Strictness * Usage: atest WMShellUnitTests:DesktopTasksControllerTest */ @SmallTest -@RunWith(AndroidTestingRunner::class) +@RunWith(ParameterizedAndroidJunit4::class) @ExperimentalCoroutinesApi @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) -class DesktopTasksControllerTest : ShellTestCase() { +class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() { - @JvmField @Rule val setFlagsRule = SetFlagsRule() + @JvmField @Rule val setFlagsRule = SetFlagsRule(flags) @Mock lateinit var testExecutor: ShellExecutor @Mock lateinit var shellCommandHandler: ShellCommandHandler @@ -245,6 +249,10 @@ class DesktopTasksControllerTest : ShellTestCase() { @Mock private lateinit var desktopWallpaperActivityTokenProvider: DesktopWallpaperActivityTokenProvider + @Mock + private lateinit var overviewToDesktopTransitionObserver: OverviewToDesktopTransitionObserver + @Mock private lateinit var desksOrganizer: DesksOrganizer + @Mock private lateinit var userProfileContexts: UserProfileContexts private lateinit var controller: DesktopTasksController private lateinit var shellInit: ShellInit @@ -339,6 +347,7 @@ class DesktopTasksControllerTest : ShellTestCase() { ) .thenReturn(ExitResult.NoExit) whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(wallpaperToken) + whenever(userProfileContexts[anyInt()]).thenReturn(context) controller = createController() controller.setSplitScreenController(splitScreenController) @@ -356,6 +365,8 @@ class DesktopTasksControllerTest : ShellTestCase() { assumeTrue(ENABLE_SHELL_TRANSITIONS) taskRepository = userRepositories.current + taskRepository.addDesk(displayId = DEFAULT_DISPLAY, deskId = DEFAULT_DISPLAY) + taskRepository.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = DEFAULT_DISPLAY) } private fun createController() = @@ -392,6 +403,9 @@ class DesktopTasksControllerTest : ShellTestCase() { desktopTilingDecorViewModel, desktopWallpaperActivityTokenProvider, Optional.of(bubbleController), + overviewToDesktopTransitionObserver, + desksOrganizer, + userProfileContexts, ) @After @@ -610,7 +624,12 @@ class DesktopTasksControllerTest : ShellTestCase() { Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY, Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY, ) + @DisableFlags( + /** TODO: b/362720497 - re-enable when activation is implemented. */ + Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND + ) fun showDesktopApps_onSecondaryDisplay_desktopWallpaperEnabled_perDisplayWallpaperEnabled_shouldShowWallpaper() { + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val homeTask = setUpHomeTask(SECOND_DISPLAY) val task1 = setUpFreeformTask(SECOND_DISPLAY) val task2 = setUpFreeformTask(SECOND_DISPLAY) @@ -631,8 +650,13 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) - @DisableFlags(Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY) + @DisableFlags( + Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY, + /** TODO: b/362720497 - re-enable when activation is implemented. */ + Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, + ) fun showDesktopApps_onSecondaryDisplay_desktopWallpaperEnabled_shouldNotShowWallpaper() { + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val homeTask = setUpHomeTask(SECOND_DISPLAY) val task1 = setUpFreeformTask(SECOND_DISPLAY) val task2 = setUpFreeformTask(SECOND_DISPLAY) @@ -671,8 +695,13 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test - @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) + @DisableFlags( + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY, + /** TODO: b/362720497 - re-enable when activation is implemented. */ + Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, + ) fun showDesktopApps_onSecondaryDisplay_desktopWallpaperDisabled_shouldNotMoveLauncher() { + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val homeTask = setUpHomeTask(SECOND_DISPLAY) val task1 = setUpFreeformTask(SECOND_DISPLAY) val task2 = setUpFreeformTask(SECOND_DISPLAY) @@ -774,6 +803,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay_desktopWallpaperDisabled() { + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY) val taskDefaultDisplay = setUpFreeformTask(DEFAULT_DISPLAY) setUpHomeTask(SECOND_DISPLAY) @@ -794,6 +824,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay_desktopWallpaperEnabled() { + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY) val taskDefaultDisplay = setUpFreeformTask(DEFAULT_DISPLAY) setUpHomeTask(SECOND_DISPLAY) @@ -880,6 +911,8 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun visibleTaskCount_twoTasksVisibleOnDifferentDisplays_returnsOne() { + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) + taskRepository.setActiveDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) setUpHomeTask() setUpFreeformTask(DEFAULT_DISPLAY).also(::markTaskVisible) setUpFreeformTask(SECOND_DISPLAY).also(::markTaskVisible) @@ -1473,6 +1506,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val fullscreenTaskDefault = setUpFullscreenTask(displayId = DEFAULT_DISPLAY) markTaskHidden(freeformTaskDefault) + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val homeTaskSecond = setUpHomeTask(displayId = SECOND_DISPLAY) val freeformTaskSecond = setUpFreeformTask(displayId = SECOND_DISPLAY) markTaskHidden(freeformTaskSecond) @@ -1670,6 +1704,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun moveToFullscreen_secondDisplayTaskHasFreeform_secondDisplayNotAffected() { val taskDefaultDisplay = setUpFreeformTask(displayId = DEFAULT_DISPLAY) + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val taskSecondDisplay = setUpFreeformTask(displayId = SECOND_DISPLAY) controller.moveToFullscreen(taskDefaultDisplay.taskId, transitionSource = UNKNOWN) @@ -1850,6 +1885,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun moveToNextDisplay_moveFromFirstToSecondDisplay() { // Set up two display ids + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) whenever(rootTaskDisplayAreaOrganizer.displayIds) .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) // Create a mock for the target display area: second display @@ -1879,6 +1915,7 @@ class DesktopTasksControllerTest : ShellTestCase() { whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) .thenReturn(defaultDisplayArea) + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val task = setUpFreeformTask(displayId = SECOND_DISPLAY) controller.moveToNextDisplay(task.taskId) @@ -1898,6 +1935,7 @@ class DesktopTasksControllerTest : ShellTestCase() { ) fun moveToNextDisplay_wallpaperOnSystemUser_reorderWallpaperToBack() { // Set up two display ids + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) whenever(rootTaskDisplayAreaOrganizer.displayIds) .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) // Create a mock for the target display area: second display @@ -1922,6 +1960,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER) fun moveToNextDisplay_wallpaperNotOnSystemUser_removeWallpaper() { // Set up two display ids + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) whenever(rootTaskDisplayAreaOrganizer.displayIds) .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) // Create a mock for the target display area: second display @@ -2046,6 +2085,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @EnableFlags(FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT) fun moveToNextDisplay_defaultBoundsWhenDestinationTooSmall() { + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) // Set up two display ids whenever(rootTaskDisplayAreaOrganizer.displayIds) .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) @@ -2087,6 +2127,7 @@ class DesktopTasksControllerTest : ShellTestCase() { FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT, ) fun moveToNextDisplay_destinationGainGlobalFocus() { + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) // Set up two display ids whenever(rootTaskDisplayAreaOrganizer.displayIds) .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) @@ -3155,6 +3196,8 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun handleRequest_closeTransition_singleTaskNoToken_secondaryDisplay_launchesHome() { + taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) + taskRepository.setActiveDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val task = setUpFreeformTask(displayId = SECOND_DISPLAY) whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) @@ -4930,7 +4973,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) fun shouldPlayDesktopAnimation_notShowingDesktop_doesNotPlay() { - val triggerTask = setUpFullscreenTask(displayId = 5) + val triggerTask = setUpFullscreenTask(displayId = DEFAULT_DISPLAY) taskRepository.setTaskInFullImmersiveState( displayId = triggerTask.displayId, taskId = triggerTask.taskId, @@ -4948,7 +4991,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) fun shouldPlayDesktopAnimation_notOpening_doesNotPlay() { - val triggerTask = setUpFreeformTask(displayId = 5) + val triggerTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY) taskRepository.setTaskInFullImmersiveState( displayId = triggerTask.displayId, taskId = triggerTask.taskId, @@ -4966,7 +5009,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) fun shouldPlayDesktopAnimation_notImmersive_doesNotPlay() { - val triggerTask = setUpFreeformTask(displayId = 5) + val triggerTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY) taskRepository.setTaskInFullImmersiveState( displayId = triggerTask.displayId, taskId = triggerTask.taskId, @@ -4985,8 +5028,8 @@ class DesktopTasksControllerTest : ShellTestCase() { @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) fun shouldPlayDesktopAnimation_fullscreenEntersDesktop_plays() { // At least one freeform task to be in a desktop. - val existingTask = setUpFreeformTask(displayId = 5) - val triggerTask = setUpFullscreenTask(displayId = 5) + val existingTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY) + val triggerTask = setUpFullscreenTask(displayId = DEFAULT_DISPLAY) assertThat(controller.isDesktopModeShowing(triggerTask.displayId)).isTrue() taskRepository.setTaskInFullImmersiveState( displayId = existingTask.displayId, @@ -5005,7 +5048,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) fun shouldPlayDesktopAnimation_fullscreenStaysFullscreen_doesNotPlay() { - val triggerTask = setUpFullscreenTask(displayId = 5) + val triggerTask = setUpFullscreenTask(displayId = DEFAULT_DISPLAY) assertThat(controller.isDesktopModeShowing(triggerTask.displayId)).isFalse() assertThat( @@ -5020,8 +5063,8 @@ class DesktopTasksControllerTest : ShellTestCase() { @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) fun shouldPlayDesktopAnimation_freeformStaysInDesktop_plays() { // At least one freeform task to be in a desktop. - val existingTask = setUpFreeformTask(displayId = 5) - val triggerTask = setUpFreeformTask(displayId = 5, active = false) + val existingTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY) + val triggerTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY, active = false) assertThat(controller.isDesktopModeShowing(triggerTask.displayId)).isTrue() taskRepository.setTaskInFullImmersiveState( displayId = existingTask.displayId, @@ -5040,7 +5083,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) fun shouldPlayDesktopAnimation_freeformExitsDesktop_doesNotPlay() { - val triggerTask = setUpFreeformTask(displayId = 5, active = false) + val triggerTask = setUpFreeformTask(displayId = DEFAULT_DISPLAY, active = false) assertThat(controller.isDesktopModeShowing(triggerTask.displayId)).isFalse() assertThat( @@ -5051,6 +5094,19 @@ class DesktopTasksControllerTest : ShellTestCase() { .isFalse() } + @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun testCreateDesk() { + val currentDeskCount = taskRepository.getNumberOfDesks(DEFAULT_DISPLAY) + whenever(desksOrganizer.createDesk(eq(DEFAULT_DISPLAY), any())).thenAnswer { invocation -> + (invocation.arguments[1] as DesksOrganizer.OnCreateCallback).onCreated(deskId = 5) + } + + controller.createDesk(DEFAULT_DISPLAY) + + assertThat(taskRepository.getNumberOfDesks(DEFAULT_DISPLAY)).isEqualTo(currentDeskCount + 1) + } + private class RunOnStartTransitionCallback : ((IBinder) -> Unit) { var invocations = 0 private set @@ -5384,6 +5440,11 @@ class DesktopTasksControllerTest : ShellTestCase() { val STABLE_BOUNDS = Rect(0, 0, 1000, 1000) const val MAX_TASK_LIMIT = 6 private const val TASKBAR_FRAME_HEIGHT = 200 + + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> = + FlagsParameterization.allCombinationsOf(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt index e85901bbd9d4..554b09f130bd 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt @@ -180,6 +180,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun addPendingMinimizeTransition_taskIsNotMinimized() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val task = setUpFreeformTask() markTaskHidden(task) @@ -190,6 +192,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun onTransitionReady_noPendingTransition_taskIsNotMinimized() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val task = setUpFreeformTask() markTaskHidden(task) @@ -203,6 +207,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun onTransitionReady_differentPendingTransition_taskIsNotMinimized() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val pendingTransition = Binder() val taskTransition = Binder() val task = setUpFreeformTask() @@ -219,6 +225,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun onTransitionReady_pendingTransition_noTaskChange_taskVisible_taskIsNotMinimized() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val transition = Binder() val task = setUpFreeformTask() markTaskVisible(task) @@ -232,6 +240,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun onTransitionReady_pendingTransition_noTaskChange_taskInvisible_taskIsMinimized() { val transition = Binder() + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val task = setUpFreeformTask() markTaskHidden(task) addPendingMinimizeChange(transition, taskId = task.taskId) @@ -243,6 +253,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun onTransitionReady_pendingTransition_changeTaskToBack_taskIsMinimized() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val transition = Binder() val task = setUpFreeformTask() addPendingMinimizeChange(transition, taskId = task.taskId) @@ -257,6 +269,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun onTransitionReady_pendingTransition_changeTaskToBack_boundsSaved() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val bounds = Rect(0, 0, 200, 200) val transition = Binder() val task = setUpFreeformTask() @@ -280,6 +294,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun onTransitionReady_transitionMergedFromPending_taskIsMinimized() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val mergedTransition = Binder() val newTransition = Binder() val task = setUpFreeformTask() @@ -302,6 +318,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) fun removeLeftoverMinimizedTasks_activeNonMinimizedTasksStillAround_doesNothing() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) desktopTaskRepo.addTask(displayId = DEFAULT_DISPLAY, taskId = 1, isVisible = true) desktopTaskRepo.addTask(displayId = DEFAULT_DISPLAY, taskId = 2, isVisible = true) desktopTaskRepo.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = 2) @@ -318,6 +336,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) fun removeLeftoverMinimizedTasks_noMinimizedTasks_doesNothing() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val wct = WindowContainerTransaction() desktopTasksLimiter.leftoverMinimizedTasksRemover.removeLeftoverMinimizedTasks( DEFAULT_DISPLAY, @@ -330,6 +350,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) fun removeLeftoverMinimizedTasks_onlyMinimizedTasksLeft_removesAllMinimizedTasks() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val task1 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) desktopTaskRepo.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task1.taskId) @@ -351,6 +373,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) fun removeLeftoverMinimizedTasks_onlyMinimizedTasksLeft_backNavEnabled_doesNothing() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val task1 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) val task2 = setUpFreeformTask(displayId = DEFAULT_DISPLAY) desktopTaskRepo.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = task1.taskId) @@ -364,6 +388,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun addAndGetMinimizeTaskChanges_tasksWithinLimit_noTaskMinimized() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() } val wct = WindowContainerTransaction() @@ -380,6 +406,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun addAndGetMinimizeTaskChanges_tasksAboveLimit_backTaskMinimized() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) // The following list will be ordered bottom -> top, as the last task is moved to top last. val tasks = (1..MAX_TASK_LIMIT).map { setUpFreeformTask() } @@ -399,6 +427,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun addAndGetMinimizeTaskChanges_nonMinimizedTasksWithinLimit_noTaskMinimized() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val tasks = (1..MAX_TASK_LIMIT).map { setUpFreeformTask() } desktopTaskRepo.minimizeTask(displayId = DEFAULT_DISPLAY, taskId = tasks[0].taskId) @@ -416,6 +446,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun getTaskToMinimize_tasksWithinLimit_returnsNull() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val tasks = (1..MAX_TASK_LIMIT).map { setUpFreeformTask() } val minimizedTask = @@ -426,6 +458,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun getTaskToMinimize_tasksAboveLimit_returnsBackTask() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val tasks = (1..MAX_TASK_LIMIT + 1).map { setUpFreeformTask() } val minimizedTask = @@ -437,6 +471,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun getTaskToMinimize_tasksAboveLimit_otherLimit_returnsBackTask() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) desktopTasksLimiter = DesktopTasksLimiter( transitions, @@ -458,6 +494,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun getTaskToMinimize_withNewTask_tasksAboveLimit_returnsBackTask() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val tasks = (1..MAX_TASK_LIMIT).map { setUpFreeformTask() } val minimizedTask = @@ -472,6 +510,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun getTaskToMinimize_tasksAtLimit_newIntentReturnsBackTask() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val tasks = (1..MAX_TASK_LIMIT).map { setUpFreeformTask() } val minimizedTask = desktopTasksLimiter.getTaskIdToMinimize( @@ -486,6 +526,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun minimizeTransitionReadyAndFinished_logsJankInstrumentationBeginAndEnd() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() } val transition = Binder() val task = setUpFreeformTask() @@ -510,6 +552,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun minimizeTransitionReadyAndAborted_logsJankInstrumentationBeginAndCancel() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() } val transition = Binder() val task = setUpFreeformTask() @@ -534,6 +578,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun minimizeTransitionReadyAndMerged_logsJankInstrumentationBeginAndEnd() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() } val mergedTransition = Binder() val newTransition = Binder() @@ -566,6 +612,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun getMinimizingTask_pendingTaskTransition_returnsTask() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val transition = Binder() val task = setUpFreeformTask() addPendingMinimizeChange( @@ -582,6 +630,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun getMinimizingTask_activeTaskTransition_returnsTask() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val transition = Binder() val task = setUpFreeformTask() addPendingMinimizeChange( @@ -613,6 +663,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun getUnminimizingTask_pendingTaskTransition_returnsTask() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val transition = Binder() val task = setUpFreeformTask() addPendingUnminimizeChange( @@ -632,6 +684,8 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun getUnminimizingTask_activeTaskTransition_returnsTask() { + desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) + desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val transition = Binder() val task = setUpFreeformTask() addPendingMinimizeChange( diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt index aee8821a63f6..8b6cafb10df4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt @@ -35,6 +35,7 @@ object DesktopTestHelpers { ): RunningTaskInfo = TestRunningTaskInfoBuilder() .setDisplayId(displayId) + .setParentTaskId(displayId) .setToken(MockToken().token()) .setActivityType(ACTIVITY_TYPE_STANDARD) .setWindowingMode(WINDOWING_MODE_FREEFORM) @@ -73,10 +74,14 @@ object DesktopTestHelpers { .setLastActiveTime(100) .build() + /** + * Create a new System Modal task builder, i.e. a builder for a task with only transparent + * activities. + */ + fun createSystemModalTaskBuilder(displayId: Int = DEFAULT_DISPLAY): TestRunningTaskInfoBuilder = + createFullscreenTaskBuilder(displayId).setActivityStackTransparent(true).setNumActivities(1) + /** Create a new System Modal task, i.e. a task with only transparent activities. */ fun createSystemModalTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo = - createFullscreenTaskBuilder(displayId) - .setActivityStackTransparent(true) - .setNumActivities(1) - .build() + createSystemModalTaskBuilder(displayId).build() } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/OverviewToDesktopTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/OverviewToDesktopTransitionObserverTest.kt new file mode 100644 index 000000000000..490c42f980e3 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/OverviewToDesktopTransitionObserverTest.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.desktopmode + +import android.os.Binder +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.transition.Transitions +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.spy +import org.mockito.Mockito.verify +import org.mockito.kotlin.mock + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class OverviewToDesktopTransitionObserverTest : ShellTestCase() { + + @Mock private lateinit var transitions: Transitions + + @Mock private lateinit var moveToDesktopCallback: IMoveToDesktopCallback + + private val testExecutor = mock<ShellExecutor>() + private lateinit var shellInit: ShellInit + private lateinit var transitionObserver: OverviewToDesktopTransitionObserver + private val token = Binder() + + @Before + fun setup() { + shellInit = spy(ShellInit(testExecutor)) + transitionObserver = OverviewToDesktopTransitionObserver(transitions, shellInit) + } + + @Test + fun moveToDesktop_onTransitionEnd_invokesCallback() { + transitionObserver.addPendingOverviewTransition(token, moveToDesktopCallback) + + transitionObserver.onTransitionFinished(token, false) + + verify(moveToDesktopCallback).onTaskMovedToDesktop() + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt index 1569f9dc9b10..463ae1d0a80c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.desktopmode.compatui +import android.content.Intent import android.os.Binder import android.testing.AndroidTestingRunner import android.view.SurfaceControl @@ -29,7 +30,9 @@ import com.android.wm.shell.desktopmode.DesktopRepository import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTaskBuilder import com.android.wm.shell.desktopmode.DesktopTestHelpers.createSystemModalTask +import com.android.wm.shell.desktopmode.DesktopTestHelpers.createSystemModalTaskBuilder import com.android.wm.shell.desktopmode.DesktopUserRepositories +import com.android.wm.shell.desktopmode.DesktopWallpaperActivity import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.TransitionInfoBuilder import com.android.wm.shell.transition.Transitions @@ -116,6 +119,19 @@ class SystemModalsTransitionHandlerTest : ShellTestCase() { } @Test + fun startAnimation_launchingWallpaperTask_doesNotAnimate() { + val wallpaperTask = + createSystemModalTaskBuilder().setBaseIntent(createWallpaperIntent()).build() + val info = + TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, wallpaperTask).build() + + assertThat(transitionHandler.startAnimation(Binder(), info, startT, finishT) {}).isFalse() + } + + private fun createWallpaperIntent() = + Intent().apply { setComponent(DesktopWallpaperActivity.wallpaperActivityComponent) } + + @Test fun startAnimation_launchingFullscreenTask_doesNotAnimate() { val info = TransitionInfoBuilder(TRANSIT_OPEN) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt index 5475032f35a9..493a8c83c48e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt @@ -29,7 +29,6 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.desktopmode.CaptionState import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository import com.android.wm.shell.desktopmode.education.AppHandleEducationController.Companion.APP_HANDLE_EDUCATION_DELAY_MILLIS -import com.android.wm.shell.desktopmode.education.AppHandleEducationController.Companion.APP_HANDLE_EDUCATION_TIMEOUT_MILLIS import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatastoreRepository import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource @@ -47,7 +46,6 @@ import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -113,10 +111,10 @@ class AppHandleEducationControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - fun init_appHandleVisible_shouldCallShowEducationTooltip() = + fun init_appHandleVisible_shouldCallShowEducationTooltipAndMarkAsViewed() = testScope.runTest { // App handle is visible. Should show education tooltip. - setShouldShowAppHandleEducation(true) + setShouldShowDesktopModeEducation(true) // Simulate app handle visible. testCaptionStateFlow.value = createAppHandleState() @@ -124,6 +122,38 @@ class AppHandleEducationControllerTest : ShellTestCase() { waitForBufferDelay() verify(mockTooltipController, times(1)).showEducationTooltip(any(), any()) + verify(mockDataStoreRepository, times(1)) + .updateAppHandleHintViewedTimestampMillis(eq(true)) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) + fun init_appHandleVisibleAndMenuExpanded_shouldCallShowEducationTooltipAndMarkAsViewed() = + testScope.runTest { + setShouldShowDesktopModeEducation(true) + + // Simulate app handle visible and handle menu is expanded. + testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = true) + waitForBufferDelay() + + verify(mockTooltipController, times(1)).showEducationTooltip(any(), any()) + verify(mockDataStoreRepository, times(1)) + .updateEnterDesktopModeHintViewedTimestampMillis(eq(true)) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) + fun init_appHeaderVisible_shouldCallShowEducationTooltipAndMarkAsViewed() = + testScope.runTest { + setShouldShowDesktopModeEducation(true) + + // Simulate app header visible. + testCaptionStateFlow.value = createAppHeaderState() + waitForBufferDelay() + + verify(mockTooltipController, times(1)).showEducationTooltip(any(), any()) + verify(mockDataStoreRepository, times(1)) + .updateExitDesktopModeHintViewedTimestampMillis(eq(true)) } @Test @@ -133,7 +163,7 @@ class AppHandleEducationControllerTest : ShellTestCase() { // App handle visible but education aconfig flag disabled, should not show education // tooltip. whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(false) - setShouldShowAppHandleEducation(true) + setShouldShowDesktopModeEducation(true) // Simulate app handle visible. testCaptionStateFlow.value = createAppHandleState() @@ -145,12 +175,11 @@ class AppHandleEducationControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - fun init_shouldShowAppHandleEducationReturnsFalse_shouldNotCallShowEducationTooltip() = + fun init_shouldShowDesktopModeEducationReturnsFalse_shouldNotCallShowEducationTooltip() = testScope.runTest { - // App handle is visible but [shouldShowAppHandleEducation] api returns false, should - // not - // show education tooltip. - setShouldShowAppHandleEducation(false) + // App handle is visible but [shouldShowDesktopModeEducation] api returns false, should + // not show education tooltip. + setShouldShowDesktopModeEducation(false) // Simulate app handle visible. testCaptionStateFlow.value = createAppHandleState() @@ -165,7 +194,7 @@ class AppHandleEducationControllerTest : ShellTestCase() { fun init_appHandleNotVisible_shouldNotCallShowEducationTooltip() = testScope.runTest { // App handle is not visible, should not show education tooltip. - setShouldShowAppHandleEducation(true) + setShouldShowDesktopModeEducation(true) // Simulate app handle is not visible. testCaptionStateFlow.value = CaptionState.NoCaption @@ -184,7 +213,7 @@ class AppHandleEducationControllerTest : ShellTestCase() { // Mark app handle hint viewed. testDataStoreFlow.value = createWindowingEducationProto(appHandleHintViewedTimestampMillis = 123L) - setShouldShowAppHandleEducation(true) + setShouldShowDesktopModeEducation(true) // Simulate app handle visible. testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = false) @@ -196,231 +225,95 @@ class AppHandleEducationControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - fun overridePrerequisite_appHandleHintViewedAlready_shouldCallShowEducationTooltip() = + fun init_enterDesktopModeHintViewedAlready_shouldNotCallShowEducationTooltip() = testScope.runTest { - // App handle is visible but app handle hint has been viewed before. - // But as we are overriding prerequisite conditions, we should show app - // handle tooltip. + // App handle is visible but app handle hint has been viewed before, + // should not show education tooltip. // Mark app handle hint viewed. testDataStoreFlow.value = - createWindowingEducationProto(appHandleHintViewedTimestampMillis = 123L) - val systemPropertiesKey = - "persist.desktop_windowing_app_handle_education_override_conditions" - whenever(SystemProperties.getBoolean(eq(systemPropertiesKey), anyBoolean())) - .thenReturn(true) - setShouldShowAppHandleEducation(true) + createWindowingEducationProto(enterDesktopModeHintViewedTimestampMillis = 123L) + setShouldShowDesktopModeEducation(true) // Simulate app handle visible. - testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = false) - // Wait for first tooltip to showup. - waitForBufferDelay() - - verify(mockTooltipController, times(1)).showEducationTooltip(any(), any()) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - fun init_appHandleExpanded_shouldMarkAppHandleHintUsed() = - testScope.runTest { - setShouldShowAppHandleEducation(false) - - // Simulate app handle visible and expanded. testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = true) - // Wait for some time before verifying + // Wait for first tooltip to showup. waitForBufferDelay() - verify(mockDataStoreRepository, times(1)) - .updateAppHandleHintUsedTimestampMillis(eq(true)) + verify(mockTooltipController, never()).showEducationTooltip(any(), any()) } @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - fun init_showFirstTooltip_shouldMarkAppHandleHintViewed() = + fun init_exitDesktopModeHintViewedAlready_shouldNotCallShowEducationTooltip() = testScope.runTest { - // App handle is visible. Should show education tooltip. - setShouldShowAppHandleEducation(true) + // App handle is visible but app handle hint has been viewed before, + // should not show education tooltip. + // Mark app handle hint viewed. + testDataStoreFlow.value = + createWindowingEducationProto(exitDesktopModeHintViewedTimestampMillis = 123L) + setShouldShowDesktopModeEducation(true) // Simulate app handle visible. - testCaptionStateFlow.value = createAppHandleState() + testCaptionStateFlow.value = createAppHeaderState() // Wait for first tooltip to showup. waitForBufferDelay() - verify(mockDataStoreRepository, times(1)) - .updateAppHandleHintViewedTimestampMillis(eq(true)) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - @Ignore("b/371527084: revisit testcase after refactoring original logic") - fun showWindowingImageButtonTooltip_appHandleExpanded_shouldCallShowEducationTooltipTwice() = - testScope.runTest { - // After first tooltip is dismissed, app handle is expanded. Should show second - // education - // tooltip. - showAndDismissFirstTooltip() - - // Simulate app handle expanded. - testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = true) - // Wait for next tooltip to showup. - waitForBufferDelay() - - // [showEducationTooltip] should be called twice, once for each tooltip. - verify(mockTooltipController, times(2)).showEducationTooltip(any(), any()) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - @Ignore("b/371527084: revisit testcase after refactoring original logic") - fun showWindowingImageButtonTooltip_appHandleExpandedAfterTimeout_shouldCallShowEducationTooltipOnce() = - testScope.runTest { - // After first tooltip is dismissed, app handle is expanded after timeout. Should not - // show - // second education tooltip. - showAndDismissFirstTooltip() - - // Wait for timeout to occur, after this timeout we should not listen for further - // triggers - // anymore. - advanceTimeBy(APP_HANDLE_EDUCATION_TIMEOUT_BUFFER_MILLIS) - runCurrent() - // Simulate app handle expanded. - testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = true) - // Wait for next tooltip to showup. - waitForBufferDelay() - - // [showEducationTooltip] should be called once, just for the first tooltip. - verify(mockTooltipController, times(1)).showEducationTooltip(any(), any()) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - @Ignore("b/371527084: revisit testcase after refactoring original logic") - fun showWindowingImageButtonTooltip_appHandleExpandedTwice_shouldCallShowEducationTooltipTwice() = - testScope.runTest { - // After first tooltip is dismissed, app handle is expanded twice. Should show second - // education tooltip only once. - showAndDismissFirstTooltip() - - // Simulate app handle expanded. - testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = true) - // Wait for next tooltip to showup. - waitForBufferDelay() - // Simulate app handle being expanded twice. - testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = true) - waitForBufferDelay() - - // [showEducationTooltip] should not be called thrice, even if app handle was expanded - // twice. Should be called twice, once for each tooltip. - verify(mockTooltipController, times(2)).showEducationTooltip(any(), any()) + verify(mockTooltipController, never()).showEducationTooltip(any(), any()) } @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - @Ignore("b/371527084: revisit testcase after refactoring original logic") - fun showWindowingImageButtonTooltip_appHandleNotExpanded_shouldCallShowEducationTooltipOnce() = + fun overridePrerequisite_appHandleHintViewedAlready_shouldCallShowEducationTooltip() = testScope.runTest { - // After first tooltip is dismissed, app handle is not expanded. Should not show second - // education tooltip. - showAndDismissFirstTooltip() + // App handle is visible but app handle hint has been viewed before. + // But as we are overriding prerequisite conditions, we should show app + // handle tooltip. + // Mark app handle hint viewed. + testDataStoreFlow.value = + createWindowingEducationProto(appHandleHintViewedTimestampMillis = 123L) + val systemPropertiesKey = "persist.windowing_force_show_desktop_mode_education" + whenever(SystemProperties.getBoolean(eq(systemPropertiesKey), anyBoolean())) + .thenReturn(true) + setShouldShowDesktopModeEducation(true) - // Simulate app handle visible but not expanded. + // Simulate app handle visible. testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = false) - // Wait for next tooltip to showup. + // Wait for first tooltip to showup. waitForBufferDelay() - // [showEducationTooltip] should be called once, just for the first tooltip. verify(mockTooltipController, times(1)).showEducationTooltip(any(), any()) } @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - @Ignore("b/371527084: revisit testcase after refactoring original logic") - fun showExitWindowingButtonTooltip_appHeaderVisible_shouldCallShowEducationTooltipThrice() = - testScope.runTest { - // After first two tooltips are dismissed, app header is visible. Should show third - // education tooltip. - showAndDismissFirstTooltip() - showAndDismissSecondTooltip() - - // Simulate app header visible. - testCaptionStateFlow.value = createAppHeaderState() - // Wait for next tooltip to showup. - waitForBufferDelay() - - verify(mockTooltipController, times(3)).showEducationTooltip(any(), any()) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - @Ignore("b/371527084: revisit testcase after refactoring original logic") - fun showExitWindowingButtonTooltip_appHeaderVisibleAfterTimeout_shouldCallShowEducationTooltipTwice() = - testScope.runTest { - // After first two tooltips are dismissed, app header is visible after timeout. Should - // not - // show third education tooltip. - showAndDismissFirstTooltip() - showAndDismissSecondTooltip() - - // Wait for timeout to occur, after this timeout we should not listen for further - // triggers - // anymore. - advanceTimeBy(APP_HANDLE_EDUCATION_TIMEOUT_BUFFER_MILLIS) - runCurrent() - // Simulate app header visible. - testCaptionStateFlow.value = createAppHeaderState() - // Wait for next tooltip to showup. - waitForBufferDelay() - - verify(mockTooltipController, times(2)).showEducationTooltip(any(), any()) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - @Ignore("b/371527084: revisit testcase after refactoring original logic") - fun showExitWindowingButtonTooltip_appHeaderVisibleTwice_shouldCallShowEducationTooltipThrice() = + fun clickAppHandleHint_openHandleMenuCallbackInvoked() = testScope.runTest { - // After first two tooltips are dismissed, app header is visible twice. Should show - // third - // education tooltip only once. - showAndDismissFirstTooltip() - showAndDismissSecondTooltip() - - // Simulate app header visible. - testCaptionStateFlow.value = createAppHeaderState() - // Wait for next tooltip to showup. - waitForBufferDelay() - testCaptionStateFlow.value = createAppHeaderState() - // Wait for next tooltip to showup. + // App handle is visible. Should show education tooltip. + setShouldShowDesktopModeEducation(true) + val mockOpenHandleMenuCallback: (Int) -> Unit = mock() + val mockToDesktopModeCallback: (Int, DesktopModeTransitionSource) -> Unit = mock() + educationController.setAppHandleEducationTooltipCallbacks( + mockOpenHandleMenuCallback, + mockToDesktopModeCallback, + ) + // Simulate app handle visible. + testCaptionStateFlow.value = createAppHandleState() + // Wait for first tooltip to showup. waitForBufferDelay() - verify(mockTooltipController, times(3)).showEducationTooltip(any(), any()) - } - - @Test - @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - @Ignore("b/371527084: revisit testcase after refactoring original logic") - fun showExitWindowingButtonTooltip_appHeaderExpanded_shouldCallShowEducationTooltipTwice() = - testScope.runTest { - // After first two tooltips are dismissed, app header is visible but expanded. Should - // not - // show third education tooltip. - showAndDismissFirstTooltip() - showAndDismissSecondTooltip() - - // Simulate app header visible. - testCaptionStateFlow.value = createAppHeaderState(isHeaderMenuExpanded = true) - // Wait for next tooltip to showup. - waitForBufferDelay() + verify(mockTooltipController, atLeastOnce()) + .showEducationTooltip(educationConfigCaptor.capture(), any()) + educationConfigCaptor.lastValue.onEducationClickAction.invoke() - verify(mockTooltipController, times(2)).showEducationTooltip(any(), any()) + verify(mockOpenHandleMenuCallback, times(1)).invoke(any()) } @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - fun setAppHandleEducationTooltipCallbacks_onAppHandleTooltipClicked_callbackInvoked() = + fun clickEnterDesktopModeHint_toDesktopModeCallbackInvoked() = testScope.runTest { // App handle is visible. Should show education tooltip. - setShouldShowAppHandleEducation(true) + setShouldShowDesktopModeEducation(true) val mockOpenHandleMenuCallback: (Int) -> Unit = mock() val mockToDesktopModeCallback: (Int, DesktopModeTransitionSource) -> Unit = mock() educationController.setAppHandleEducationTooltipCallbacks( @@ -428,7 +321,7 @@ class AppHandleEducationControllerTest : ShellTestCase() { mockToDesktopModeCallback, ) // Simulate app handle visible. - testCaptionStateFlow.value = createAppHandleState() + testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = true) // Wait for first tooltip to showup. waitForBufferDelay() @@ -436,68 +329,41 @@ class AppHandleEducationControllerTest : ShellTestCase() { .showEducationTooltip(educationConfigCaptor.capture(), any()) educationConfigCaptor.lastValue.onEducationClickAction.invoke() - verify(mockOpenHandleMenuCallback, times(1)).invoke(any()) + verify(mockToDesktopModeCallback, times(1)) + .invoke(any(), eq(DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON)) } @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) - @Ignore("b/371527084: revisit testcase after refactoring original logic") - fun setAppHandleEducationTooltipCallbacks_onWindowingImageButtonTooltipClicked_callbackInvoked() = + fun clickExitDesktopModeHint_openHandleMenuCallbackInvoked() = testScope.runTest { - // After first tooltip is dismissed, app handle is expanded. Should show second - // education - // tooltip. - showAndDismissFirstTooltip() + // App handle is visible. Should show education tooltip. + setShouldShowDesktopModeEducation(true) val mockOpenHandleMenuCallback: (Int) -> Unit = mock() val mockToDesktopModeCallback: (Int, DesktopModeTransitionSource) -> Unit = mock() educationController.setAppHandleEducationTooltipCallbacks( mockOpenHandleMenuCallback, mockToDesktopModeCallback, ) - // Simulate app handle expanded. - testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = true) - // Wait for next tooltip to showup. + // Simulate app handle visible. + testCaptionStateFlow.value = createAppHeaderState() + // Wait for first tooltip to showup. waitForBufferDelay() verify(mockTooltipController, atLeastOnce()) .showEducationTooltip(educationConfigCaptor.capture(), any()) educationConfigCaptor.lastValue.onEducationClickAction.invoke() - verify(mockToDesktopModeCallback, times(1)).invoke(any(), any()) + verify(mockOpenHandleMenuCallback, times(1)).invoke(any()) } - private suspend fun TestScope.showAndDismissFirstTooltip() { - setShouldShowAppHandleEducation(true) - // Simulate app handle visible. - testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = false) - // Wait for first tooltip to showup. - waitForBufferDelay() - // [shouldShowAppHandleEducation] should return false as education has been viewed - // before. - setShouldShowAppHandleEducation(false) - // Dismiss previous tooltip, after this we should listen for next tooltip's trigger. - captureAndInvokeOnDismissAction() + private suspend fun setShouldShowDesktopModeEducation(shouldShowDesktopModeEducation: Boolean) { + whenever(mockEducationFilter.shouldShowDesktopModeEducation(any<CaptionState.AppHandle>())) + .thenReturn(shouldShowDesktopModeEducation) + whenever(mockEducationFilter.shouldShowDesktopModeEducation(any<CaptionState.AppHeader>())) + .thenReturn(shouldShowDesktopModeEducation) } - private fun TestScope.showAndDismissSecondTooltip() { - // Simulate app handle expanded. - testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = true) - // Wait for next tooltip to showup. - waitForBufferDelay() - // Dismiss previous tooltip, after this we should listen for next tooltip's trigger. - captureAndInvokeOnDismissAction() - } - - private fun captureAndInvokeOnDismissAction() { - verify(mockTooltipController, atLeastOnce()) - .showEducationTooltip(educationConfigCaptor.capture(), any()) - educationConfigCaptor.lastValue.onDismissAction.invoke() - } - - private suspend fun setShouldShowAppHandleEducation(shouldShowAppHandleEducation: Boolean) = - whenever(mockEducationFilter.shouldShowAppHandleEducation(any())) - .thenReturn(shouldShowAppHandleEducation) - /** * Class under test waits for some time before showing education, simulate advance time before * verifying or moving forward @@ -510,7 +376,5 @@ class AppHandleEducationControllerTest : ShellTestCase() { private companion object { val APP_HANDLE_EDUCATION_DELAY_BUFFER_MILLIS: Long = APP_HANDLE_EDUCATION_DELAY_MILLIS + 1000L - val APP_HANDLE_EDUCATION_TIMEOUT_BUFFER_MILLIS: Long = - APP_HANDLE_EDUCATION_TIMEOUT_MILLIS + 1000L } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt index 4db883d13551..31dfc78902b2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationDatastoreRepositoryTest.kt @@ -123,6 +123,24 @@ class AppHandleEducationDatastoreRepositoryTest { } @Test + fun updateEnterDesktopModeHintViewedTimestampMillis_updatesDatastoreProto() = + runTest(StandardTestDispatcher()) { + datastoreRepository.updateEnterDesktopModeHintViewedTimestampMillis(true) + + val result = testDatastore.data.first().hasEnterDesktopModeHintViewedTimestampMillis() + assertThat(result).isEqualTo(true) + } + + @Test + fun updateExitDesktopModeHintViewedTimestampMillis_updatesDatastoreProto() = + runTest(StandardTestDispatcher()) { + datastoreRepository.updateExitDesktopModeHintViewedTimestampMillis(true) + + val result = testDatastore.data.first().hasExitDesktopModeHintViewedTimestampMillis() + assertThat(result).isEqualTo(true) + } + + @Test fun updateAppHandleHintUsedTimestampMillis_updatesDatastoreProto() = runTest(StandardTestDispatcher()) { datastoreRepository.updateAppHandleHintUsedTimestampMillis(true) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt index 2fc36efb1a41..218226240c0f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationFilterTest.kt @@ -89,9 +89,9 @@ class AppHandleEducationFilterTest : ShellTestCase() { } @Test - fun shouldShowAppHandleEducation_isTriggerValid_returnsTrue() = runTest { - // setup() makes sure that all of the conditions satisfy and #shouldShowAppHandleEducation - // should return true + fun shouldShowDesktopModeEducation_isTriggerValid_returnsTrue() = runTest { + // setup() makes sure that all of the conditions satisfy and + // [shouldShowDesktopModeEducation] should return true val windowingEducationProto = createWindowingEducationProto( appUsageStats = mapOf(GMAIL_PACKAGE_NAME to 4), @@ -99,16 +99,15 @@ class AppHandleEducationFilterTest : ShellTestCase() { ) `when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto) - val result = educationFilter.shouldShowAppHandleEducation(createAppHandleState()) + val result = educationFilter.shouldShowDesktopModeEducation(createAppHandleState()) assertThat(result).isTrue() } @Test - fun shouldShowAppHandleEducation_focusAppNotInAllowlist_returnsFalse() = runTest { + fun shouldShowDesktopModeEducation_focusAppNotInAllowlist_returnsFalse() = runTest { // Pass Youtube as current focus app, it is not in allowlist hence - // #shouldShowAppHandleEducation - // should return false + // [shouldShowDesktopModeEducation] should return false testableResources.addOverride( R.array.desktop_windowing_app_handle_education_allowlist_apps, arrayOf(GMAIL_PACKAGE_NAME), @@ -122,16 +121,15 @@ class AppHandleEducationFilterTest : ShellTestCase() { createAppHandleState(createTaskInfo(runningTaskPackageName = YOUTUBE_PACKAGE_NAME)) `when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto) - val result = educationFilter.shouldShowAppHandleEducation(captionState) + val result = educationFilter.shouldShowDesktopModeEducation(captionState) assertThat(result).isFalse() } @Test - fun shouldShowAppHandleEducation_timeSinceSetupIsNotSufficient_returnsFalse() = runTest { - // Time required to have passed setup is > 100 years, hence #shouldShowAppHandleEducation - // should - // return false + fun shouldShowDesktopModeEducation_timeSinceSetupIsNotSufficient_returnsFalse() = runTest { + // Time required to have passed setup is > 100 years, hence [shouldShowDesktopModeEducation] + // should return false testableResources.addOverride( R.integer.desktop_windowing_education_required_time_since_setup_seconds, MAX_VALUE, @@ -143,50 +141,15 @@ class AppHandleEducationFilterTest : ShellTestCase() { ) `when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto) - val result = educationFilter.shouldShowAppHandleEducation(createAppHandleState()) - - assertThat(result).isFalse() - } - - @Test - fun shouldShowAppHandleEducation_appHandleHintViewedBefore_returnsFalse() = runTest { - // App handle hint has been viewed before, hence #shouldShowAppHandleEducation should return - // false - val windowingEducationProto = - createWindowingEducationProto( - appUsageStats = mapOf(GMAIL_PACKAGE_NAME to 4), - appHandleHintViewedTimestampMillis = 123L, - appUsageStatsLastUpdateTimestampMillis = Long.MAX_VALUE, - ) - `when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto) - - val result = educationFilter.shouldShowAppHandleEducation(createAppHandleState()) - - assertThat(result).isFalse() - } - - @Test - fun shouldShowAppHandleEducation_appHandleHintUsedBefore_returnsFalse() = runTest { - // App handle hint has been used before, hence #shouldShowAppHandleEducation should return - // false - val windowingEducationProto = - createWindowingEducationProto( - appUsageStats = mapOf(GMAIL_PACKAGE_NAME to 4), - appHandleHintUsedTimestampMillis = 123L, - appUsageStatsLastUpdateTimestampMillis = Long.MAX_VALUE, - ) - `when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto) - - val result = educationFilter.shouldShowAppHandleEducation(createAppHandleState()) + val result = educationFilter.shouldShowDesktopModeEducation(createAppHandleState()) assertThat(result).isFalse() } @Test - fun shouldShowAppHandleEducation_doesNotHaveMinAppUsage_returnsFalse() = runTest { + fun shouldShowDesktopModeEducation_doesNotHaveMinAppUsage_returnsFalse() = runTest { // Simulate that gmail app has been launched twice before, minimum app launch count is 3, - // hence - // #shouldShowAppHandleEducation should return false + // hence [shouldShowDesktopModeEducation] should return false testableResources.addOverride(R.integer.desktop_windowing_education_min_app_launch_count, 3) val windowingEducationProto = createWindowingEducationProto( @@ -195,13 +158,13 @@ class AppHandleEducationFilterTest : ShellTestCase() { ) `when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto) - val result = educationFilter.shouldShowAppHandleEducation(createAppHandleState()) + val result = educationFilter.shouldShowDesktopModeEducation(createAppHandleState()) assertThat(result).isFalse() } @Test - fun shouldShowAppHandleEducation_appUsageStatsStale_queryAppUsageStats() = runTest { + fun shouldShowDesktopModeEducation_appUsageStatsStale_queryAppUsageStats() = runTest { // UsageStats caching interval is set to 0ms, that means caching should happen very // frequently testableResources.addOverride( @@ -209,8 +172,7 @@ class AppHandleEducationFilterTest : ShellTestCase() { 0, ) // The DataStore currently holds a proto object where Gmail's app launch count is recorded - // as 4. - // This value exceeds the minimum required count of 3. + // as 4. This value exceeds the minimum required count of 3. testableResources.addOverride(R.integer.desktop_windowing_education_min_app_launch_count, 3) val windowingEducationProto = createWindowingEducationProto( @@ -223,40 +185,20 @@ class AppHandleEducationFilterTest : ShellTestCase() { .thenReturn(mapOf(GMAIL_PACKAGE_NAME to UsageStats().apply { mAppLaunchCount = 2 })) `when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto) - val result = educationFilter.shouldShowAppHandleEducation(createAppHandleState()) + val result = educationFilter.shouldShowDesktopModeEducation(createAppHandleState()) // Result should be false as queried usage stats should be considered to determine the - // result - // instead of cached stats - assertThat(result).isFalse() - } - - @Test - fun shouldShowAppHandleEducation_appHandleMenuExpanded_returnsFalse() = runTest { - val windowingEducationProto = - createWindowingEducationProto( - appUsageStats = mapOf(GMAIL_PACKAGE_NAME to 4), - appUsageStatsLastUpdateTimestampMillis = Long.MAX_VALUE, - ) - // Simulate app handle menu is expanded - val captionState = createAppHandleState(isHandleMenuExpanded = true) - `when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto) - - val result = educationFilter.shouldShowAppHandleEducation(captionState) - - // We should not show app handle education if app menu is expanded + // result instead of cached stats assertThat(result).isFalse() } @Test - fun shouldShowAppHandleEducation_overridePrerequisite_returnsTrue() = runTest { + fun shouldShowDesktopModeEducation_overridePrerequisite_returnsTrue() = runTest { // Simulate that gmail app has been launched twice before, minimum app launch count is 3, - // hence - // #shouldShowAppHandleEducation should return false. But as we are overriding prerequisite - // conditions, #shouldShowAppHandleEducation should return true. + // hence [shouldShowDesktopModeEducation] should return false. But as we are overriding + // prerequisite conditions, [shouldShowDesktopModeEducation] should return true. testableResources.addOverride(R.integer.desktop_windowing_education_min_app_launch_count, 3) - val systemPropertiesKey = - "persist.desktop_windowing_app_handle_education_override_conditions" + val systemPropertiesKey = "persist.windowing_force_show_desktop_mode_education" whenever(SystemProperties.getBoolean(eq(systemPropertiesKey), anyBoolean())) .thenReturn(true) val windowingEducationProto = @@ -266,7 +208,7 @@ class AppHandleEducationFilterTest : ShellTestCase() { ) `when`(datastoreRepository.windowingEducationProto()).thenReturn(windowingEducationProto) - val result = educationFilter.shouldShowAppHandleEducation(createAppHandleState()) + val result = educationFilter.shouldShowDesktopModeEducation(createAppHandleState()) assertThat(result).isTrue() } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt new file mode 100644 index 000000000000..a07203d86b75 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.desktopmode.multidesks + +import android.testing.AndroidTestingRunner +import android.view.Display +import android.view.SurfaceControl +import android.window.TransitionInfo +import android.window.WindowContainerTransaction +import android.window.WindowContainerTransaction.HierarchyOp +import androidx.test.filters.SmallTest +import com.android.wm.shell.ShellTaskOrganizer +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestShellExecutor +import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask +import com.android.wm.shell.sysui.ShellCommandHandler +import com.android.wm.shell.sysui.ShellInit +import com.google.common.truth.Truth.assertThat +import org.junit.Assert.assertEquals +import org.junit.Assert.assertThrows +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.mock + +/** + * Tests for [RootTaskDesksOrganizer]. + * + * Usage: atest WMShellUnitTests:RootTaskDesksOrganizerTest + */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +class RootTaskDesksOrganizerTest : ShellTestCase() { + + private val testExecutor = TestShellExecutor() + private val testShellInit = ShellInit(testExecutor) + private val mockShellCommandHandler = mock<ShellCommandHandler>() + private val mockShellTaskOrganizer = mock<ShellTaskOrganizer>() + + private lateinit var organizer: RootTaskDesksOrganizer + + @Before + fun setUp() { + organizer = + RootTaskDesksOrganizer(testShellInit, mockShellCommandHandler, mockShellTaskOrganizer) + } + + @Test + fun testCreateDesk_callsBack() { + val callback = FakeOnCreateCallback() + organizer.createDesk(Display.DEFAULT_DISPLAY, callback) + + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + + assertThat(callback.created).isTrue() + assertEquals(freeformRoot.taskId, callback.deskId) + } + + @Test + fun testOnTaskAppeared_withoutRequest_throws() { + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + + assertThrows(Exception::class.java) { + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + } + } + + @Test + fun testOnTaskAppeared_withRequestOnlyInAnotherDisplay_throws() { + organizer.createDesk(displayId = 2, FakeOnCreateCallback()) + val freeformRoot = createFreeformTask(Display.DEFAULT_DISPLAY).apply { parentTaskId = -1 } + + assertThrows(Exception::class.java) { + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + } + } + + @Test + fun testOnTaskAppeared_duplicateRoot_throws() { + organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback()) + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + + assertThrows(Exception::class.java) { + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + } + } + + @Test + fun testOnTaskVanished_removesRoot() { + val callback = FakeOnCreateCallback() + organizer.createDesk(Display.DEFAULT_DISPLAY, callback) + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + + organizer.onTaskVanished(freeformRoot) + + assertThat(organizer.roots.contains(freeformRoot.taskId)).isFalse() + } + + @Test + fun testDesktopWindowAppearsInDesk() { + organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback()) + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + val child = createFreeformTask().apply { parentTaskId = freeformRoot.taskId } + + organizer.onTaskAppeared(child, SurfaceControl()) + + assertThat(organizer.roots[freeformRoot.taskId].children).contains(child.taskId) + } + + @Test + fun testDesktopWindowDisappearsFromDesk() { + organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback()) + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + val child = createFreeformTask().apply { parentTaskId = freeformRoot.taskId } + + organizer.onTaskAppeared(child, SurfaceControl()) + organizer.onTaskVanished(child) + + assertThat(organizer.roots[freeformRoot.taskId].children).doesNotContain(child.taskId) + } + + @Test + fun testRemoveDesk() { + organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback()) + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + + val wct = WindowContainerTransaction() + organizer.removeDesk(wct, freeformRoot.taskId) + + assertThat( + wct.hierarchyOps.any { hop -> + hop.type == HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK && + hop.container == freeformRoot.token.asBinder() + } + ) + .isTrue() + } + + @Test + fun testRemoveDesk_didNotExist_throws() { + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + + val wct = WindowContainerTransaction() + assertThrows(Exception::class.java) { organizer.removeDesk(wct, freeformRoot.taskId) } + } + + @Test + fun testActivateDesk() { + organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback()) + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + + val wct = WindowContainerTransaction() + organizer.activateDesk(wct, freeformRoot.taskId) + + assertThat( + wct.hierarchyOps.any { hop -> + hop.type == HierarchyOp.HIERARCHY_OP_TYPE_REORDER && + hop.toTop && + hop.container == freeformRoot.token.asBinder() + } + ) + .isTrue() + assertThat( + wct.hierarchyOps.any { hop -> + hop.type == HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT && + hop.container == freeformRoot.token.asBinder() + } + ) + .isTrue() + } + + @Test + fun testActivateDesk_didNotExist_throws() { + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + + val wct = WindowContainerTransaction() + assertThrows(Exception::class.java) { organizer.activateDesk(wct, freeformRoot.taskId) } + } + + @Test + fun testMoveTaskToDesk() { + organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback()) + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + + val desktopTask = createFreeformTask().apply { parentTaskId = -1 } + val wct = WindowContainerTransaction() + organizer.moveTaskToDesk(wct, freeformRoot.taskId, desktopTask) + + assertThat( + wct.hierarchyOps.any { hop -> + hop.isReparent && + hop.toTop && + hop.container == desktopTask.token.asBinder() && + hop.newParent == freeformRoot.token.asBinder() + } + ) + .isTrue() + } + + @Test + fun testMoveTaskToDesk_didNotExist_throws() { + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + + val desktopTask = createFreeformTask().apply { parentTaskId = -1 } + val wct = WindowContainerTransaction() + assertThrows(Exception::class.java) { + organizer.moveTaskToDesk(wct, freeformRoot.taskId, desktopTask) + } + } + + @Test + fun testGetDeskAtEnd() { + organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback()) + val freeformRoot = createFreeformTask().apply { parentTaskId = -1 } + organizer.onTaskAppeared(freeformRoot, SurfaceControl()) + + val task = createFreeformTask().apply { parentTaskId = freeformRoot.taskId } + val endDesk = + organizer.getDeskAtEnd( + TransitionInfo.Change(task.token, SurfaceControl()).apply { taskInfo = task } + ) + + assertThat(endDesk).isEqualTo(freeformRoot.taskId) + } + + private class FakeOnCreateCallback : DesksOrganizer.OnCreateCallback { + var deskId: Int? = null + val created: Boolean + get() = deskId != null + + override fun onCreated(deskId: Int) { + this.deskId = deskId + } + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt index a3c441698905..9a8f264e98a4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.desktopmode.persistence import android.os.UserManager +import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner @@ -24,6 +25,7 @@ import android.view.Display.DEFAULT_DISPLAY import androidx.test.filters.SmallTest import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_HSUM import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE +import com.android.window.flags.Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.desktopmode.DesktopUserRepositories @@ -85,7 +87,9 @@ class DesktopRepositoryInitializerTest : ShellTestCase() { @Test @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE, FLAG_ENABLE_DESKTOP_WINDOWING_HSUM) - fun initWithPersistence_multipleUsers_addedCorrectly() = + /** TODO: b/362720497 - add multi-desk version when implemented. */ + @DisableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun initWithPersistence_multipleUsers_addedCorrectly_multiDesksDisabled() = runTest(StandardTestDispatcher()) { whenever(persistentRepository.getUserDesktopRepositoryMap()) .thenReturn( @@ -145,7 +149,9 @@ class DesktopRepositoryInitializerTest : ShellTestCase() { @Test @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE) - fun initWithPersistence_singleUser_addedCorrectly() = + /** TODO: b/362720497 - add multi-desk version when implemented. */ + @DisableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun initWithPersistence_singleUser_addedCorrectly_multiDesksDisabled() = runTest(StandardTestDispatcher()) { whenever(persistentRepository.getUserDesktopRepositoryMap()) .thenReturn(mapOf(USER_ID_1 to desktopRepositoryState1)) @@ -156,24 +162,24 @@ class DesktopRepositoryInitializerTest : ShellTestCase() { repositoryInitializer.initialize(desktopUserRepositories) - // Desktop Repository currently returns all tasks across desktops for a specific user - // since the repository currently doesn't handle desktops. This test logic should be - // updated - // once the repository handles multiple desktops. assertThat( - desktopUserRepositories.getProfile(USER_ID_1).getActiveTasks(DEFAULT_DISPLAY) + desktopUserRepositories + .getProfile(USER_ID_1) + .getActiveTaskIdsInDesk(deskId = DEFAULT_DISPLAY) ) .containsExactly(1, 3, 4, 5) .inOrder() assertThat( desktopUserRepositories .getProfile(USER_ID_1) - .getExpandedTasksOrdered(DEFAULT_DISPLAY) + .getExpandedTasksIdsInDeskOrdered(deskId = DEFAULT_DISPLAY) ) .containsExactly(5, 1) .inOrder() assertThat( - desktopUserRepositories.getProfile(USER_ID_1).getMinimizedTasks(DEFAULT_DISPLAY) + desktopUserRepositories + .getProfile(USER_ID_1) + .getMinimizedTaskIdsInDesk(deskId = DEFAULT_DISPLAY) ) .containsExactly(3, 4) .inOrder() @@ -195,6 +201,7 @@ class DesktopRepositoryInitializerTest : ShellTestCase() { val desktop1: Desktop = Desktop.newBuilder() .setDesktopId(DESKTOP_ID_1) + .setDisplayId(DEFAULT_DISPLAY) .addAllZOrderedTasks(freeformTasksInZOrder1) .putTasksByTaskId( 1, @@ -216,6 +223,7 @@ class DesktopRepositoryInitializerTest : ShellTestCase() { val desktop2: Desktop = Desktop.newBuilder() .setDesktopId(DESKTOP_ID_2) + .setDisplayId(DEFAULT_DISPLAY) .addAllZOrderedTasks(freeformTasksInZOrder2) .putTasksByTaskId( 4, @@ -237,6 +245,7 @@ class DesktopRepositoryInitializerTest : ShellTestCase() { val desktop3: Desktop = Desktop.newBuilder() .setDesktopId(DESKTOP_ID_3) + .setDisplayId(DEFAULT_DISPLAY) .addAllZOrderedTasks(freeformTasksInZOrder3) .putTasksByTaskId( 7, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java index fa5989a3ca99..4174bbd89b76 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java @@ -46,6 +46,7 @@ import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.common.LaunchAdjacentController; +import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.desktopmode.DesktopUserRepositories; @@ -89,6 +90,8 @@ public final class FreeformTaskListenerTests extends ShellTestCase { @Mock private DesktopTasksController mDesktopTasksController; @Mock + private DesktopModeLoggerTransitionObserver mDesktopModeLoggerTransitionObserver; + @Mock private LaunchAdjacentController mLaunchAdjacentController; @Mock private TaskChangeListener mTaskChangeListener; @@ -114,6 +117,7 @@ public final class FreeformTaskListenerTests extends ShellTestCase { mTaskOrganizer, Optional.of(mDesktopUserRepositories), Optional.of(mDesktopTasksController), + mDesktopModeLoggerTransitionObserver, mLaunchAdjacentController, mWindowDecorViewModel, Optional.of(mTaskChangeListener)); @@ -159,7 +163,8 @@ public final class FreeformTaskListenerTests extends ShellTestCase { } @Test - public void focusTaskChanged_addsFreeformTaskToRepo() { + @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) + public void focusTaskChanged_noTransitionObserversFlag_addsFreeformTaskToRepo() { ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); task.isFocused = true; @@ -171,6 +176,19 @@ public final class FreeformTaskListenerTests extends ShellTestCase { } @Test + @EnableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) + public void focusTaskChanged_enableTransitionObservers_freeformTaskNotAddedToRepo() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + task.isFocused = true; + + mFreeformTaskListener.onFocusTaskChanged(task); + + verify(mDesktopUserRepositories.getCurrent(), never()) + .addTask(task.displayId, task.taskId, task.isVisible); + } + + @Test public void focusTaskChanged_fullscreenTaskNotAddedToRepo() { ActivityManager.RunningTaskInfo fullscreenTask = new TestRunningTaskInfoBuilder() @@ -269,6 +287,19 @@ public final class FreeformTaskListenerTests extends ShellTestCase { } @Test + public void onTaskVanished_withDesktopModeLogger_forwards() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + task.isVisible = true; + mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); + + mFreeformTaskListener.onTaskVanished(task); + + verify(mDesktopModeLoggerTransitionObserver).onTaskVanished(task); + } + + + @Test public void onTaskInfoChanged_withDesktopController_forwards() { ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java index 53f6cda62f55..7e68b68e469a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java @@ -87,7 +87,7 @@ public class PipAnimationControllerTest extends ShellTestCase { .getAnimator(mTaskInfo, mLeash, new Rect(), 0f, 1f); assertEquals("Expect ANIM_TYPE_ALPHA animation", - animator.getAnimationType(), PipAnimationController.ANIM_TYPE_ALPHA); + animator.getAnimationType(), PipTransitionController.ANIM_TYPE_ALPHA); } @Test @@ -101,7 +101,7 @@ public class PipAnimationControllerTest extends ShellTestCase { false /* alwaysAnimateTaskBounds */); assertEquals("Expect ANIM_TYPE_BOUNDS animation", - animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS); + animator.getAnimationType(), PipTransitionController.ANIM_TYPE_BOUNDS); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java index 2eb2c3b8e2f7..836f4c24a979 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java @@ -289,7 +289,7 @@ public class PipTaskOrganizerTest extends ShellTestCase { DisplayLayout layout = new DisplayLayout(info, mContext.getResources(), true, true); mPipDisplayLayoutState.setDisplayLayout(layout); - doReturn(PipAnimationController.ANIM_TYPE_ALPHA).when(mMockPipAnimationController) + doReturn(PipTransitionController.ANIM_TYPE_ALPHA).when(mMockPipAnimationController) .takeOneShotEnterAnimationType(); mPipTaskOrganizer.setSurfaceControlTransactionFactory( MockSurfaceControlHelper::createMockSurfaceControlTransaction); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java index ae0c9d6cbf7c..414c0147660c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java @@ -26,6 +26,7 @@ import android.os.Handler; import android.view.SurfaceControl; import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.common.DisplayController; @@ -83,12 +84,13 @@ public class SplitTestUtils { Optional<RecentTasksController> recentTasks, LaunchAdjacentController launchAdjacentController, Optional<WindowDecorViewModel> windowDecorViewModel, SplitState splitState, - Optional<DesktopTasksController> desktopTasksController) { + Optional<DesktopTasksController> desktopTasksController, + RootTaskDisplayAreaOrganizer rootTDAOrganizer) { super(context, displayId, syncQueue, taskOrganizer, mainStage, sideStage, displayController, imeController, insetsController, splitLayout, transitions, transactionPool, mainExecutor, mainHandler, recentTasks, launchAdjacentController, windowDecorViewModel, splitState, - desktopTasksController); + desktopTasksController, rootTDAOrganizer); // Prepare root task for testing. mRootTask = new TestRunningTaskInfoBuilder().build(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java index b0fdfacd7d83..4211e4682810 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java @@ -47,6 +47,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.app.ActivityManager; @@ -54,6 +55,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.view.SurfaceControl; +import android.window.DisplayAreaInfo; import android.window.IRemoteTransition; import android.window.RemoteTransition; import android.window.TransitionInfo; @@ -65,6 +67,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.icons.IconProvider; +import com.android.wm.shell.MockToken; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; @@ -121,6 +124,8 @@ public class SplitTransitionTests extends ShellTestCase { private StageTaskListener mSideStage; private StageCoordinator mStageCoordinator; private SplitScreenTransitions mSplitScreenTransitions; + private final DisplayAreaInfo mDisplayAreaInfo = new DisplayAreaInfo(new MockToken().token(), + DEFAULT_DISPLAY, 0); private ActivityManager.RunningTaskInfo mMainChild; private ActivityManager.RunningTaskInfo mSideChild; @@ -146,7 +151,9 @@ public class SplitTransitionTests extends ShellTestCase { mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool, mMainExecutor, mMainHandler, Optional.empty(), - mLaunchAdjacentController, Optional.empty(), mSplitState, Optional.empty()); + mLaunchAdjacentController, Optional.empty(), mSplitState, Optional.empty(), + mRootTDAOrganizer); + when(mRootTDAOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(mDisplayAreaInfo); mStageCoordinator.setMixedHandler(mMixedHandler); mSplitScreenTransitions = mStageCoordinator.getSplitTransitions(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java index 7a88ace3f85f..5851cbf9b933 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java @@ -17,6 +17,8 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +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.Display.DEFAULT_DISPLAY; @@ -27,11 +29,14 @@ import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSIT import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; +import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER; +import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DESKTOP_MODE; import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -39,6 +44,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -56,6 +62,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.view.SurfaceControl; +import android.window.DisplayAreaInfo; import android.window.RemoteTransition; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; @@ -64,6 +71,8 @@ import androidx.test.annotation.UiThreadTest; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import com.android.wm.shell.MockToken; +import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; @@ -94,6 +103,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Optional; +import java.util.function.Consumer; /** * Tests for {@link StageCoordinator} @@ -125,6 +135,8 @@ public class StageCoordinatorTests extends ShellTestCase { private DefaultMixedHandler mDefaultMixedHandler; @Mock private SplitState mSplitState; + @Mock + private RootTaskDisplayAreaOrganizer mRootTDAOrganizer; private final Rect mBounds1 = new Rect(10, 20, 30, 40); private final Rect mBounds2 = new Rect(5, 10, 15, 20); @@ -138,6 +150,10 @@ public class StageCoordinatorTests extends ShellTestCase { private final TestShellExecutor mMainExecutor = new TestShellExecutor(); private final ShellExecutor mAnimExecutor = new TestShellExecutor(); private final Handler mMainHandler = new Handler(Looper.getMainLooper()); + private final DisplayAreaInfo mDisplayAreaInfo = new DisplayAreaInfo(new MockToken().token(), + DEFAULT_DISPLAY, 0); + private final ActivityManager.RunningTaskInfo mMainChildTaskInfo = + new TestRunningTaskInfoBuilder().setVisible(true).build(); @Before @UiThreadTest @@ -148,9 +164,10 @@ public class StageCoordinatorTests extends ShellTestCase { mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool, mMainExecutor, mMainHandler, Optional.empty(), mLaunchAdjacentController, - Optional.empty(), mSplitState, Optional.empty())); + Optional.empty(), mSplitState, Optional.empty(), mRootTDAOrganizer)); mDividerLeash = new SurfaceControl.Builder().setName("fakeDivider").build(); + when(mRootTDAOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(mDisplayAreaInfo); when(mSplitLayout.getTopLeftBounds()).thenReturn(mBounds1); when(mSplitLayout.getBottomRightBounds()).thenReturn(mBounds2); @@ -167,6 +184,12 @@ public class StageCoordinatorTests extends ShellTestCase { mMainStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().build(); doReturn(mock(SplitDecorManager.class)).when(mMainStage).getSplitDecorManager(); doReturn(mock(SplitDecorManager.class)).when(mSideStage).getSplitDecorManager(); + + doAnswer(invocation -> { + Consumer<ActivityManager.RunningTaskInfo> consumer = invocation.getArgument(0); + consumer.accept(mMainChildTaskInfo); + return null; + }).when(mMainStage).doForAllChildTaskInfos(any()); } @Test @@ -454,6 +477,55 @@ public class StageCoordinatorTests extends ShellTestCase { int windowingMode = wctCaptor.getValue().getChanges().get(binder).getWindowingMode(); assertEquals(windowingMode, WINDOWING_MODE_UNDEFINED); } + @Test + public void testDismiss_freeformDisplay() { + mDisplayAreaInfo.configuration.windowConfiguration.setWindowingMode( + WINDOWING_MODE_FREEFORM); + when(mStageCoordinator.isSplitActive()).thenReturn(true); + + WindowContainerTransaction wct = new WindowContainerTransaction(); + mStageCoordinator.prepareExitSplitScreen(STAGE_TYPE_MAIN, wct, EXIT_REASON_DRAG_DIVIDER); + + assertEquals(wct.getChanges().get(mMainChildTaskInfo.token.asBinder()).getWindowingMode(), + WINDOWING_MODE_FULLSCREEN); + } + + @Test + public void testDismiss_freeformDisplayToDesktop() { + mDisplayAreaInfo.configuration.windowConfiguration.setWindowingMode( + WINDOWING_MODE_FREEFORM); + when(mStageCoordinator.isSplitActive()).thenReturn(true); + + WindowContainerTransaction wct = new WindowContainerTransaction(); + mStageCoordinator.prepareExitSplitScreen(STAGE_TYPE_MAIN, wct, EXIT_REASON_DESKTOP_MODE); + + WindowContainerTransaction.Change c = + wct.getChanges().get(mMainChildTaskInfo.token.asBinder()); + assertFalse(c != null && c.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); + } + + @Test + public void testDismiss_fullscreenDisplay() { + when(mStageCoordinator.isSplitActive()).thenReturn(true); + + WindowContainerTransaction wct = new WindowContainerTransaction(); + mStageCoordinator.prepareExitSplitScreen(STAGE_TYPE_MAIN, wct, EXIT_REASON_DRAG_DIVIDER); + + assertEquals(wct.getChanges().get(mMainChildTaskInfo.token.asBinder()).getWindowingMode(), + WINDOWING_MODE_UNDEFINED); + } + + @Test + public void testDismiss_fullscreenDisplayToDesktop() { + when(mStageCoordinator.isSplitActive()).thenReturn(true); + + WindowContainerTransaction wct = new WindowContainerTransaction(); + mStageCoordinator.prepareExitSplitScreen(STAGE_TYPE_MAIN, wct, EXIT_REASON_DESKTOP_MODE); + + WindowContainerTransaction.Change c = + wct.getChanges().get(mMainChildTaskInfo.token.asBinder()); + assertFalse(c != null && c.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); + } private Transitions createTestTransitions() { ShellInit shellInit = new ShellInit(mMainExecutor); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt index b9d91e7895db..546848421302 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/WindowingEducationTestUtils.kt @@ -81,7 +81,9 @@ fun createWindowingEducationProto( appHandleHintViewedTimestampMillis: Long? = null, appHandleHintUsedTimestampMillis: Long? = null, appUsageStats: Map<String, Int>? = null, - appUsageStatsLastUpdateTimestampMillis: Long? = null + appUsageStatsLastUpdateTimestampMillis: Long? = null, + enterDesktopModeHintViewedTimestampMillis: Long? = null, + exitDesktopModeHintViewedTimestampMillis: Long? = null, ): WindowingEducationProto = WindowingEducationProto.newBuilder() .apply { @@ -91,6 +93,12 @@ fun createWindowingEducationProto( if (appHandleHintUsedTimestampMillis != null) { setAppHandleHintUsedTimestampMillis(appHandleHintUsedTimestampMillis) } + if (enterDesktopModeHintViewedTimestampMillis != null) { + setEnterDesktopModeHintViewedTimestampMillis(enterDesktopModeHintViewedTimestampMillis) + } + if (exitDesktopModeHintViewedTimestampMillis != null) { + setExitDesktopModeHintViewedTimestampMillis(exitDesktopModeHintViewedTimestampMillis) + } setAppHandleEducation( createAppHandleEducationProto(appUsageStats, appUsageStatsLastUpdateTimestampMillis)) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index b4791642663a..baccbee0893d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -642,6 +642,7 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest eq(decor.mTaskInfo.taskId), any(), eq(DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON), + anyOrNull(), anyOrNull() ) } @@ -875,7 +876,7 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest ) verify(mockDesktopTasksController, times(1)) - .moveTaskToDesktop(any(), any(), any(), anyOrNull()) + .moveTaskToDesktop(any(), any(), any(), anyOrNull(), anyOrNull()) } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt index 2207c705d7dc..0615c1d677ba 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt @@ -51,6 +51,7 @@ import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFI import java.util.function.Supplier import junit.framework.Assert import org.junit.Before +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -206,6 +207,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() { } @Test + @Ignore("Causing presubmit failure b/391717499") fun testDragResize_movesTask_doesNotShowResizeVeil() = runOnUiThread { taskPositioner.onDragPositioningStart( CTRL_TYPE_UNDEFINED, @@ -245,6 +247,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() { } @Test + @Ignore("Causing presubmit failure b/391717499") fun testDragResize_movesTaskToNewDisplay() = runOnUiThread { taskPositioner.onDragPositioningStart( CTRL_TYPE_UNDEFINED, @@ -370,6 +373,7 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() { } @Test + @Ignore("Causing presubmit failure b/391717499") fun testDragResize_drag_setBoundsNotRunIfDragEndsInDisallowedEndArea() = runOnUiThread { taskPositioner.onDragPositioningStart( CTRL_TYPE_UNDEFINED, // drag diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/WindowDecorTaskResourceLoaderTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/WindowDecorTaskResourceLoaderTest.kt index 1ec0fe794d0a..431de896f433 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/WindowDecorTaskResourceLoaderTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/WindowDecorTaskResourceLoaderTest.kt @@ -33,6 +33,7 @@ import com.android.launcher3.icons.IconProvider import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestRunningTaskInfoBuilder import com.android.wm.shell.TestShellExecutor +import com.android.wm.shell.common.UserProfileContexts import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.sysui.UserChangeListener @@ -69,6 +70,7 @@ class WindowDecorTaskResourceLoaderTest : ShellTestCase() { private val mockIconProvider = mock<IconProvider>() private val mockHeaderIconFactory = mock<BaseIconFactory>() private val mockVeilIconFactory = mock<BaseIconFactory>() + private val mMockUserProfileContexts = mock<UserProfileContexts>() private lateinit var spyContext: TestableContext private lateinit var loader: WindowDecorTaskResourceLoader @@ -83,12 +85,13 @@ class WindowDecorTaskResourceLoaderTest : ShellTestCase() { spyContext = spy(mContext) spyContext.setMockPackageManager(mockPackageManager) doReturn(spyContext).whenever(spyContext).createContextAsUser(any(), anyInt()) + doReturn(spyContext).whenever(mMockUserProfileContexts)[anyInt()] loader = WindowDecorTaskResourceLoader( - context = spyContext, shellInit = shellInit, shellController = mockShellController, shellCommandHandler = mock(), + userProfilesContexts = mMockUserProfileContexts, iconProvider = mockIconProvider, headerIconFactory = mockHeaderIconFactory, veilIconFactory = mockVeilIconFactory, @@ -170,16 +173,6 @@ class WindowDecorTaskResourceLoaderTest : ShellTestCase() { } @Test - fun testUserChange_updatesContext() { - val newUser = 5000 - val newContext = mock<Context>() - - userChangeListener.onUserChanged(newUser, newContext) - - assertThat(loader.currentUserContext).isEqualTo(newContext) - } - - @Test fun testUserChange_clearsCache() { val newUser = 5000 val newContext = mock<Context>() diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index e57148fe5a6a..3af36a404c30 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -281,7 +281,7 @@ public final class MediaRouter2 { /* executor */ null, /* onInstanceInvalidatedListener */ null); } catch (IllegalArgumentException ex) { - Log.e(TAG, "Package " + clientPackageName + " not found. Ignoring."); + Log.e(TAG, "Failed to create proxy router for package '" + clientPackageName + "'", ex); return null; } } diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig index 312f78e2b24e..94454cf9ab9b 100644 --- a/media/java/android/media/flags/media_better_together.aconfig +++ b/media/java/android/media/flags/media_better_together.aconfig @@ -173,11 +173,10 @@ flag { bug: "281072508" } - flag { - name: "enable_singleton_audio_manager_route_controller" + name: "enable_use_of_singleton_audio_manager_route_controller" is_exported: true - namespace: "media_solutions" + namespace: "media_better_together" description: "Use singleton AudioManagerRouteController shared across all users." bug: "372868909" metadata { diff --git a/media/java/android/media/flags/projection.aconfig b/media/java/android/media/flags/projection.aconfig index fa1349c61c4c..6d4f0b4f47d5 100644 --- a/media/java/android/media/flags/projection.aconfig +++ b/media/java/android/media/flags/projection.aconfig @@ -29,3 +29,13 @@ flag { is_exported: true } +flag { + namespace: "media_projection" + name: "show_stop_dialog_post_call_end" + description: "Shows a stop dialog for MediaProjection sessions that started during call and remain active after a call ends" + bug: "390343524" + metadata { + purpose: PURPOSE_BUGFIX + } + is_exported: true +} diff --git a/media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl b/media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl index e46d34e81483..3baf4d7efd65 100644 --- a/media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl +++ b/media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl @@ -18,6 +18,7 @@ package android.media.projection; import android.media.projection.MediaProjectionInfo; import android.view.ContentRecordingSession; +import android.media.projection.MediaProjectionEvent; /** {@hide} */ oneway interface IMediaProjectionWatcherCallback { @@ -35,4 +36,19 @@ oneway interface IMediaProjectionWatcherCallback { in MediaProjectionInfo info, in @nullable ContentRecordingSession session ); + + /** + * Called when a specific {@link MediaProjectionEvent} occurs during the media projection session. + * + * @param event contains the event type, which describes the nature/context of the event. + * @param info optional {@link MediaProjectionInfo} containing details about the media + projection host. + * @param session the recording session for the current media projection. Can be + * {@code null} when the recording will stop. + */ + void onMediaProjectionEvent( + in MediaProjectionEvent event, + in @nullable MediaProjectionInfo info, + in @nullable ContentRecordingSession session + ); } diff --git a/media/java/android/media/projection/MediaProjectionEvent.aidl b/media/java/android/media/projection/MediaProjectionEvent.aidl new file mode 100644 index 000000000000..34359900ce81 --- /dev/null +++ b/media/java/android/media/projection/MediaProjectionEvent.aidl @@ -0,0 +1,3 @@ +package android.media.projection; + +parcelable MediaProjectionEvent;
\ No newline at end of file diff --git a/media/java/android/media/projection/MediaProjectionEvent.java b/media/java/android/media/projection/MediaProjectionEvent.java new file mode 100644 index 000000000000..6922560c8abe --- /dev/null +++ b/media/java/android/media/projection/MediaProjectionEvent.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2025 The Android Open 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, + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.projection; + +import android.annotation.IntDef; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** @hide */ +public final class MediaProjectionEvent implements Parcelable { + + /** + * Represents various media projection events. + */ + @IntDef({PROJECTION_STARTED_DURING_CALL_AND_ACTIVE_POST_CALL}) + @Retention(RetentionPolicy.SOURCE) + public @interface EventType {} + + /** Event type for when a call ends but the session is still active. */ + public static final int PROJECTION_STARTED_DURING_CALL_AND_ACTIVE_POST_CALL = 0; + + private final @EventType int mEventType; + private final long mTimestampMillis; + + public MediaProjectionEvent(@EventType int eventType, long timestampMillis) { + mEventType = eventType; + mTimestampMillis = timestampMillis; + } + + private MediaProjectionEvent(Parcel in) { + mEventType = in.readInt(); + mTimestampMillis = in.readLong(); + } + + public @EventType int getEventType() { + return mEventType; + } + + public long getTimestampMillis() { + return mTimestampMillis; + } + + @Override + public boolean equals(Object o) { + if (o instanceof MediaProjectionEvent other) { + return mEventType == other.mEventType && mTimestampMillis == other.mTimestampMillis; + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(mEventType, mTimestampMillis); + } + + @Override + public String toString() { + return "MediaProjectionEvent{mEventType=" + mEventType + ", mTimestampMillis=" + + mTimestampMillis + "}"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mEventType); + out.writeLong(mTimestampMillis); + } + + public static final Parcelable.Creator<MediaProjectionEvent> CREATOR = + new Parcelable.Creator<>() { + @Override + public MediaProjectionEvent createFromParcel(Parcel in) { + return new MediaProjectionEvent(in); + } + + @Override + public MediaProjectionEvent[] newArray(int size) { + return new MediaProjectionEvent[size]; + } + }; +} diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java index 9cc2cca441a4..9036bf385d96 100644 --- a/media/java/android/media/projection/MediaProjectionManager.java +++ b/media/java/android/media/projection/MediaProjectionManager.java @@ -363,6 +363,19 @@ public final class MediaProjectionManager { @Nullable ContentRecordingSession session ) { } + + /** + * Called when a specific {@link MediaProjectionEvent} occurs during the media projection + * session. + * + * @param event the media projection event details. + * @param info optional details about the media projection host. + * @param session optional associated recording session details. + */ + public void onMediaProjectionEvent( + final MediaProjectionEvent event, + @Nullable MediaProjectionInfo info, + @Nullable final ContentRecordingSession session) {} } /** @hide */ @@ -405,5 +418,13 @@ public final class MediaProjectionManager { ) { mHandler.post(() -> mCallback.onRecordingSessionSet(info, session)); } + + @Override + public void onMediaProjectionEvent( + final MediaProjectionEvent event, + @Nullable MediaProjectionInfo info, + @Nullable final ContentRecordingSession session) { + mHandler.post(() -> mCallback.onMediaProjectionEvent(event, info, session)); + } } } diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java index b7269256a449..0d6d32a22dae 100644 --- a/media/java/android/media/quality/MediaQualityManager.java +++ b/media/java/android/media/quality/MediaQualityManager.java @@ -51,7 +51,6 @@ import java.util.function.Consumer; @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) @SystemService(Context.MEDIA_QUALITY_SERVICE) public final class MediaQualityManager { - // TODO: unhide the APIs for api review private static final String TAG = "MediaQualityManager"; private final IMediaQualityManager mService; @@ -123,7 +122,6 @@ public final class MediaQualityManager { public void onPictureProfileAdded(String profileId, PictureProfile profile) { synchronized (mPpLock) { for (PictureProfileCallbackRecord record : mPpCallbackRecords) { - // TODO: filter callback record record.postPictureProfileAdded(profileId, profile); } } @@ -132,7 +130,6 @@ public final class MediaQualityManager { public void onPictureProfileUpdated(String profileId, PictureProfile profile) { synchronized (mPpLock) { for (PictureProfileCallbackRecord record : mPpCallbackRecords) { - // TODO: filter callback record record.postPictureProfileUpdated(profileId, profile); } } @@ -141,7 +138,6 @@ public final class MediaQualityManager { public void onPictureProfileRemoved(String profileId, PictureProfile profile) { synchronized (mPpLock) { for (PictureProfileCallbackRecord record : mPpCallbackRecords) { - // TODO: filter callback record record.postPictureProfileRemoved(profileId, profile); } } @@ -151,7 +147,6 @@ public final class MediaQualityManager { String profileId, List<ParameterCapability> caps) { synchronized (mPpLock) { for (PictureProfileCallbackRecord record : mPpCallbackRecords) { - // TODO: filter callback record record.postParameterCapabilitiesChanged(profileId, caps); } } @@ -160,7 +155,6 @@ public final class MediaQualityManager { public void onError(String profileId, int err) { synchronized (mPpLock) { for (PictureProfileCallbackRecord record : mPpCallbackRecords) { - // TODO: filter callback record record.postError(profileId, err); } } @@ -171,7 +165,6 @@ public final class MediaQualityManager { public void onSoundProfileAdded(String profileId, SoundProfile profile) { synchronized (mSpLock) { for (SoundProfileCallbackRecord record : mSpCallbackRecords) { - // TODO: filter callback record record.postSoundProfileAdded(profileId, profile); } } @@ -180,7 +173,6 @@ public final class MediaQualityManager { public void onSoundProfileUpdated(String profileId, SoundProfile profile) { synchronized (mSpLock) { for (SoundProfileCallbackRecord record : mSpCallbackRecords) { - // TODO: filter callback record record.postSoundProfileUpdated(profileId, profile); } } @@ -189,7 +181,6 @@ public final class MediaQualityManager { public void onSoundProfileRemoved(String profileId, SoundProfile profile) { synchronized (mSpLock) { for (SoundProfileCallbackRecord record : mSpCallbackRecords) { - // TODO: filter callback record record.postSoundProfileRemoved(profileId, profile); } } @@ -199,7 +190,6 @@ public final class MediaQualityManager { String profileId, List<ParameterCapability> caps) { synchronized (mSpLock) { for (SoundProfileCallbackRecord record : mSpCallbackRecords) { - // TODO: filter callback record record.postParameterCapabilitiesChanged(profileId, caps); } } @@ -208,7 +198,6 @@ public final class MediaQualityManager { public void onError(String profileId, int err) { synchronized (mSpLock) { for (SoundProfileCallbackRecord record : mSpCallbackRecords) { - // TODO: filter callback record record.postError(profileId, err); } } diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml index 65f3edb2604c..6d917da5b814 100644 --- a/packages/InputDevices/res/values-ar/strings.xml +++ b/packages/InputDevices/res/values-ar/strings.xml @@ -56,6 +56,5 @@ <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"لغة الجبل الأسود (اللاتينية)"</string> <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"الصربية (السيريلية)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"لغة الجبل الأسود (السيريلية)"</string> - <!-- no translation found for keyboard_layout_romanian (8698989892731726903) --> - <skip /> + <string name="keyboard_layout_romanian" msgid="8698989892731726903">"الرومانية"</string> </resources> diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml index 6a46b1473089..c7a489672bb0 100644 --- a/packages/InputDevices/res/values-cs/strings.xml +++ b/packages/InputDevices/res/values-cs/strings.xml @@ -56,6 +56,5 @@ <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"černohorština (latinka)"</string> <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srbština (cyrilice)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"černohorština (cyrilice)"</string> - <!-- no translation found for keyboard_layout_romanian (8698989892731726903) --> - <skip /> + <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumunština"</string> </resources> diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml index 4cf8098fded7..85f9656dedde 100644 --- a/packages/InputDevices/res/values-iw/strings.xml +++ b/packages/InputDevices/res/values-iw/strings.xml @@ -56,6 +56,5 @@ <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"מונטנגרית (לטינית)"</string> <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"סרבית (אותיות קיריליות)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"מונטנגרית (אותיות קיריליות)"</string> - <!-- no translation found for keyboard_layout_romanian (8698989892731726903) --> - <skip /> + <string name="keyboard_layout_romanian" msgid="8698989892731726903">"רומנית"</string> </resources> diff --git a/packages/InputDevices/res/values-si/strings.xml b/packages/InputDevices/res/values-si/strings.xml index 373dfda87874..78d10101358e 100644 --- a/packages/InputDevices/res/values-si/strings.xml +++ b/packages/InputDevices/res/values-si/strings.xml @@ -56,6 +56,5 @@ <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"මොන්ටෙනේග්රීන් (ලතින්)"</string> <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"සර්බියානු (සිරිලික්)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"මොන්ටෙනේග්රීන් (සිරිලික්)"</string> - <!-- no translation found for keyboard_layout_romanian (8698989892731726903) --> - <skip /> + <string name="keyboard_layout_romanian" msgid="8698989892731726903">"රුමේනියානු"</string> </resources> diff --git a/packages/InputDevices/res/values-sq/strings.xml b/packages/InputDevices/res/values-sq/strings.xml index 36882cbf7986..066129e87769 100644 --- a/packages/InputDevices/res/values-sq/strings.xml +++ b/packages/InputDevices/res/values-sq/strings.xml @@ -56,6 +56,5 @@ <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Malazisht (latine)"</string> <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbisht (cirilike)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Malazisht (cirilike)"</string> - <!-- no translation found for keyboard_layout_romanian (8698989892731726903) --> - <skip /> + <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumanisht"</string> </resources> diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml index 1010177539b1..01d34e362c7f 100644 --- a/packages/InputDevices/res/values-uk/strings.xml +++ b/packages/InputDevices/res/values-uk/strings.xml @@ -56,6 +56,5 @@ <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Чорногорська (латиниця)"</string> <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Сербська (кирилиця)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Чорногорська (кирилиця)"</string> - <!-- no translation found for keyboard_layout_romanian (8698989892731726903) --> - <skip /> + <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румунська"</string> </resources> diff --git a/packages/InputDevices/res/values-uz/strings.xml b/packages/InputDevices/res/values-uz/strings.xml index 92e00d81c622..e63fc09b8d00 100644 --- a/packages/InputDevices/res/values-uz/strings.xml +++ b/packages/InputDevices/res/values-uz/strings.xml @@ -56,6 +56,5 @@ <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Chernogor (lotin)"</string> <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serb (kirill)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Chernogor (kirill)"</string> - <!-- no translation found for keyboard_layout_romanian (8698989892731726903) --> - <skip /> + <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumin"</string> </resources> diff --git a/packages/PackageInstaller/res/values-ko/strings.xml b/packages/PackageInstaller/res/values-ko/strings.xml index 21da3e913df3..0d9920e4cdfe 100644 --- a/packages/PackageInstaller/res/values-ko/strings.xml +++ b/packages/PackageInstaller/res/values-ko/strings.xml @@ -78,7 +78,7 @@ <string name="uninstalling" msgid="8709566347688966845">"제거 중..."</string> <string name="uninstalling_app" msgid="8866082646836981397">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> 제거 중…"</string> <string name="uninstall_done" msgid="439354138387969269">"제거를 완료했습니다."</string> - <string name="uninstall_done_app" msgid="4588850984473605768">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>를 제거했습니다."</string> + <string name="uninstall_done_app" msgid="4588850984473605768">"앱(<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>)을 삭제했습니다."</string> <string name="uninstall_done_clone_app" msgid="5578308154544195413">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> 복제 삭제됨"</string> <string name="uninstall_failed" msgid="1847750968168364332">"제거하지 못했습니다."</string> <string name="uninstall_failed_app" msgid="5506028705017601412">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>을(를) 제거하지 못했습니다."</string> diff --git a/packages/SettingsLib/BannerMessagePreference/Android.bp b/packages/SettingsLib/BannerMessagePreference/Android.bp index 77e2cc735895..182daeb45d7c 100644 --- a/packages/SettingsLib/BannerMessagePreference/Android.bp +++ b/packages/SettingsLib/BannerMessagePreference/Android.bp @@ -28,4 +28,8 @@ android_library { sdk_version: "system_current", min_sdk_version: "28", + apex_available: [ + "//apex_available:platform", + "com.android.healthfitness", + ], } diff --git a/packages/SettingsLib/DisplayUtils/Android.bp b/packages/SettingsLib/DisplayUtils/Android.bp index 279bb70d81bf..62630b5a9331 100644 --- a/packages/SettingsLib/DisplayUtils/Android.bp +++ b/packages/SettingsLib/DisplayUtils/Android.bp @@ -15,6 +15,4 @@ android_library { ], srcs: ["src/**/*.java"], - - min_sdk_version: "21", } diff --git a/packages/SettingsLib/DisplayUtils/src/com/android/settingslib/display/DisplayDensityConfiguration.java b/packages/SettingsLib/DisplayUtils/src/com/android/settingslib/display/DisplayDensityConfiguration.java index 284a9025de64..127e628fbd2f 100644 --- a/packages/SettingsLib/DisplayUtils/src/com/android/settingslib/display/DisplayDensityConfiguration.java +++ b/packages/SettingsLib/DisplayUtils/src/com/android/settingslib/display/DisplayDensityConfiguration.java @@ -16,13 +16,20 @@ package com.android.settingslib.display; +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.display.DisplayManager; import android.os.AsyncTask; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; +import android.view.Display; +import android.view.DisplayInfo; import android.view.IWindowManager; import android.view.WindowManagerGlobal; +import java.util.function.Predicate; + /** Utility methods for controlling the display density. */ public class DisplayDensityConfiguration { private static final String LOG_TAG = "DisplayDensityConfig"; @@ -85,4 +92,42 @@ public class DisplayDensityConfiguration { } }); } + + /** + * Asynchronously applies display density changes to all displays that satisfy the predicate. + * + * <p>The change will be applied to the user specified by the value of + * {@link UserHandle#myUserId()} at the time the method is called. + * + * @param context The context + * @param predicate Determines which displays to set the density to + * @param density The density to force + */ + public static void setForcedDisplayDensity(@NonNull Context context, + @NonNull Predicate<DisplayInfo> predicate, final int density) { + final int userId = UserHandle.myUserId(); + DisplayManager dm = context.getSystemService(DisplayManager.class); + AsyncTask.execute(() -> { + try { + for (Display display : dm.getDisplays( + DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) { + int displayId = display.getDisplayId(); + DisplayInfo info = new DisplayInfo(); + if (!display.getDisplayInfo(info)) { + Log.w(LOG_TAG, "Unable to save forced display density setting " + + "for display " + displayId); + continue; + } + if (!predicate.test(info)) { + continue; + } + + final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); + wm.setForcedDisplayDensityForUser(displayId, density, userId); + } + } catch (RemoteException exc) { + Log.w(LOG_TAG, "Unable to save forced display density setting"); + } + }); + } } diff --git a/packages/SettingsLib/Graph/graph.proto b/packages/SettingsLib/Graph/graph.proto index 33a7df4c6ba8..a834947144a0 100644 --- a/packages/SettingsLib/Graph/graph.proto +++ b/packages/SettingsLib/Graph/graph.proto @@ -26,6 +26,14 @@ message PreferenceScreenProto { optional PreferenceGroupProto root = 2; // If the preference screen provides complete hierarchy by source code. optional bool complete_hierarchy = 3; + // Parameterized screens (not recursive, provided on the top level only) + repeated ParameterizedPreferenceScreenProto parameterized_screens = 4; +} + +// Proto of parameterized preference screen +message ParameterizedPreferenceScreenProto { + optional BundleProto args = 1; + optional PreferenceScreenProto screen = 2; } // Proto of PreferenceGroup. diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt index 51813a1c9aab..27ce1c7246e6 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt @@ -18,16 +18,24 @@ package com.android.settingslib.graph import android.app.Application import android.os.Bundle +import android.os.Parcelable +import android.os.SystemClock import com.android.settingslib.graph.proto.PreferenceGraphProto import com.android.settingslib.ipc.ApiHandler +import com.android.settingslib.ipc.ApiPermissionChecker import com.android.settingslib.ipc.MessageCodec +import com.android.settingslib.metadata.PreferenceRemoteOpMetricsLogger +import com.android.settingslib.metadata.PreferenceScreenCoordinate import com.android.settingslib.metadata.PreferenceScreenRegistry import com.android.settingslib.preference.PreferenceScreenProvider import java.util.Locale /** API to get preference graph. */ -abstract class GetPreferenceGraphApiHandler( - private val preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>> +class GetPreferenceGraphApiHandler( + override val id: Int, + private val permissionChecker: ApiPermissionChecker<GetPreferenceGraphRequest>, + private val metricsLogger: PreferenceRemoteOpMetricsLogger? = null, + private val preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>> = emptySet(), ) : ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> { override val requestCodec: MessageCodec<GetPreferenceGraphRequest> @@ -36,37 +44,56 @@ abstract class GetPreferenceGraphApiHandler( override val responseCodec: MessageCodec<PreferenceGraphProto> get() = PreferenceGraphProtoCodec + override fun hasPermission( + application: Application, + callingPid: Int, + callingUid: Int, + request: GetPreferenceGraphRequest, + ) = permissionChecker.hasPermission(application, callingPid, callingUid, request) + override suspend fun invoke( application: Application, callingPid: Int, callingUid: Int, request: GetPreferenceGraphRequest, ): PreferenceGraphProto { - val builder = PreferenceGraphBuilder.of(application, callingPid, callingUid, request) - if (request.screenKeys.isEmpty()) { - PreferenceScreenRegistry.preferenceScreenMetadataFactories.forEachKeyAsync { - builder.addPreferenceScreenFromRegistry(it) - } - for (provider in preferenceScreenProviders) { - builder.addPreferenceScreenProvider(provider) + val elapsedRealtime = SystemClock.elapsedRealtime() + var success = false + try { + val builder = PreferenceGraphBuilder.of(application, callingPid, callingUid, request) + if (request.screens.isEmpty()) { + val factories = PreferenceScreenRegistry.preferenceScreenMetadataFactories + factories.forEachAsync { _, factory -> builder.addPreferenceScreen(factory) } + for (provider in preferenceScreenProviders) { + builder.addPreferenceScreenProvider(provider) + } } + val result = builder.build() + success = true + return result + } finally { + metricsLogger?.logGraphApi( + application, + callingUid, + success, + SystemClock.elapsedRealtime() - elapsedRealtime, + ) } - return builder.build() } } /** * Request of [GetPreferenceGraphApiHandler]. * - * @param screenKeys screen keys of the preference graph - * @param visitedScreens keys of the visited preference screen + * @param screens screens of the preference graph + * @param visitedScreens visited preference screens * @param locale locale of the preference graph */ data class GetPreferenceGraphRequest @JvmOverloads constructor( - val screenKeys: Set<String> = setOf(), - val visitedScreens: Set<String> = setOf(), + val screens: Set<PreferenceScreenCoordinate> = setOf(), + val visitedScreens: Set<PreferenceScreenCoordinate> = setOf(), val locale: Locale? = null, val flags: Int = PreferenceGetterFlags.ALL, val includeValueDescriptor: Boolean = true, @@ -75,26 +102,32 @@ constructor( object GetPreferenceGraphRequestCodec : MessageCodec<GetPreferenceGraphRequest> { override fun encode(data: GetPreferenceGraphRequest): Bundle = Bundle(4).apply { - putStringArray(KEY_SCREEN_KEYS, data.screenKeys.toTypedArray()) - putStringArray(KEY_VISITED_KEYS, data.visitedScreens.toTypedArray()) + putParcelableArray(KEY_SCREENS, data.screens.toTypedArray()) + putParcelableArray(KEY_VISITED_SCREENS, data.visitedScreens.toTypedArray()) putString(KEY_LOCALE, data.locale?.toLanguageTag()) putInt(KEY_FLAGS, data.flags) } + @Suppress("DEPRECATION") override fun decode(data: Bundle): GetPreferenceGraphRequest { - val screenKeys = data.getStringArray(KEY_SCREEN_KEYS) ?: arrayOf() - val visitedScreens = data.getStringArray(KEY_VISITED_KEYS) ?: arrayOf() + data.classLoader = PreferenceScreenCoordinate::class.java.classLoader + val screens = data.getParcelableArray(KEY_SCREENS) ?: arrayOf() + val visitedScreens = data.getParcelableArray(KEY_VISITED_SCREENS) ?: arrayOf() fun String?.toLocale() = if (this != null) Locale.forLanguageTag(this) else null + fun Array<Parcelable>.toScreenCoordinates() = + buildSet(size) { + for (element in this@toScreenCoordinates) add(element as PreferenceScreenCoordinate) + } return GetPreferenceGraphRequest( - screenKeys.toSet(), - visitedScreens.toSet(), + screens.toScreenCoordinates(), + visitedScreens.toScreenCoordinates(), data.getString(KEY_LOCALE).toLocale(), data.getInt(KEY_FLAGS), ) } - private const val KEY_SCREEN_KEYS = "k" - private const val KEY_VISITED_KEYS = "v" + private const val KEY_SCREENS = "s" + private const val KEY_VISITED_SCREENS = "v" private const val KEY_LOCALE = "l" private const val KEY_FLAGS = "f" } diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterApi.kt index 6fc6b5405eb2..1d4e2c9e1bef 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterApi.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterApi.kt @@ -17,6 +17,7 @@ package com.android.settingslib.graph import android.app.Application +import android.os.SystemClock import androidx.annotation.IntDef import com.android.settingslib.graph.proto.PreferenceProto import com.android.settingslib.ipc.ApiDescriptor @@ -24,6 +25,8 @@ import com.android.settingslib.ipc.ApiHandler import com.android.settingslib.ipc.ApiPermissionChecker import com.android.settingslib.metadata.PreferenceCoordinate import com.android.settingslib.metadata.PreferenceHierarchyNode +import com.android.settingslib.metadata.PreferenceRemoteOpMetricsLogger +import com.android.settingslib.metadata.PreferenceScreenCoordinate import com.android.settingslib.metadata.PreferenceScreenRegistry /** @@ -37,6 +40,7 @@ class PreferenceGetterRequest(val preferences: Array<PreferenceCoordinate>, val /** Error code of preference getter request. */ @Target(AnnotationTarget.TYPE) @IntDef( + PreferenceGetterErrorCode.OK, PreferenceGetterErrorCode.NOT_FOUND, PreferenceGetterErrorCode.DISALLOW, PreferenceGetterErrorCode.INTERNAL_ERROR, @@ -44,6 +48,8 @@ class PreferenceGetterRequest(val preferences: Array<PreferenceCoordinate>, val @Retention(AnnotationRetention.SOURCE) annotation class PreferenceGetterErrorCode { companion object { + /** Preference value is returned. */ + const val OK = 0 /** Preference is not found. */ const val NOT_FOUND = 1 /** Disallow to get preference value (e.g. uid not allowed). */ @@ -80,6 +86,7 @@ class PreferenceGetterApiDescriptor(override val id: Int) : class PreferenceGetterApiHandler( override val id: Int, private val permissionChecker: ApiPermissionChecker<PreferenceGetterRequest>, + private val metricsLogger: PreferenceRemoteOpMetricsLogger? = null, ) : ApiHandler<PreferenceGetterRequest, PreferenceGetterResponse> { override fun hasPermission( @@ -95,14 +102,27 @@ class PreferenceGetterApiHandler( callingUid: Int, request: PreferenceGetterRequest, ): PreferenceGetterResponse { + val elapsedRealtime = SystemClock.elapsedRealtime() val errors = mutableMapOf<PreferenceCoordinate, Int>() val preferences = mutableMapOf<PreferenceCoordinate, PreferenceProto>() val flags = request.flags - for ((screenKey, coordinates) in request.preferences.groupBy { it.screenKey }) { - val screenMetadata = PreferenceScreenRegistry.create(application, screenKey) + val groups = + request.preferences.groupBy { PreferenceScreenCoordinate(it.screenKey, it.args) } + for ((screen, coordinates) in groups) { + val screenMetadata = PreferenceScreenRegistry.create(application, screen) if (screenMetadata == null) { + val latencyMs = SystemClock.elapsedRealtime() - elapsedRealtime for (coordinate in coordinates) { errors[coordinate] = PreferenceGetterErrorCode.NOT_FOUND + metricsLogger?.logGetterApi( + application, + callingUid, + coordinate, + null, + null, + PreferenceGetterErrorCode.NOT_FOUND, + latencyMs, + ) } continue } @@ -117,27 +137,48 @@ class PreferenceGetterApiHandler( val node = nodes[coordinate.key] if (node == null) { errors[coordinate] = PreferenceGetterErrorCode.NOT_FOUND + metricsLogger?.logGetterApi( + application, + callingUid, + coordinate, + null, + null, + PreferenceGetterErrorCode.NOT_FOUND, + SystemClock.elapsedRealtime() - elapsedRealtime, + ) continue } val metadata = node.metadata - try { - val preferenceProto = - metadata.toProto( - application, - callingPid, - callingUid, - screenMetadata, - metadata.key == screenMetadata.key, - flags, - ) - if (flags == PreferenceGetterFlags.VALUE && !preferenceProto.hasValue()) { - errors[coordinate] = PreferenceGetterErrorCode.DISALLOW - } else { - preferences[coordinate] = preferenceProto + val errorCode = + try { + val preferenceProto = + metadata.toProto( + application, + callingPid, + callingUid, + screenMetadata, + metadata.key == screenMetadata.key, + flags, + ) + if (flags == PreferenceGetterFlags.VALUE && !preferenceProto.hasValue()) { + PreferenceGetterErrorCode.DISALLOW + } else { + preferences[coordinate] = preferenceProto + PreferenceGetterErrorCode.OK + } + } catch (e: Exception) { + PreferenceGetterErrorCode.INTERNAL_ERROR } - } catch (e: Exception) { - errors[coordinate] = PreferenceGetterErrorCode.INTERNAL_ERROR - } + if (errorCode != PreferenceGetterErrorCode.OK) errors[coordinate] = errorCode + metricsLogger?.logGetterApi( + application, + callingUid, + coordinate, + screenMetadata, + metadata, + errorCode, + SystemClock.elapsedRealtime() - elapsedRealtime, + ) } } return PreferenceGetterResponse(errors, preferences) diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt index c0d244989044..4290437b0d02 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt @@ -40,6 +40,7 @@ import com.android.settingslib.graph.proto.PreferenceProto import com.android.settingslib.graph.proto.PreferenceProto.ActionTarget import com.android.settingslib.graph.proto.PreferenceScreenProto import com.android.settingslib.graph.proto.TextProto +import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_ARGS import com.android.settingslib.metadata.IntRangeValuePreference import com.android.settingslib.metadata.PersistentPreference import com.android.settingslib.metadata.PreferenceAvailabilityProvider @@ -47,7 +48,10 @@ import com.android.settingslib.metadata.PreferenceHierarchy import com.android.settingslib.metadata.PreferenceMetadata import com.android.settingslib.metadata.PreferenceRestrictionProvider import com.android.settingslib.metadata.PreferenceScreenBindingKeyProvider +import com.android.settingslib.metadata.PreferenceScreenCoordinate import com.android.settingslib.metadata.PreferenceScreenMetadata +import com.android.settingslib.metadata.PreferenceScreenMetadataFactory +import com.android.settingslib.metadata.PreferenceScreenMetadataParameterizedFactory import com.android.settingslib.metadata.PreferenceScreenRegistry import com.android.settingslib.metadata.PreferenceSummaryProvider import com.android.settingslib.metadata.PreferenceTitleProvider @@ -72,15 +76,19 @@ private constructor( PreferenceScreenFactory(context.ofLocale(request.locale)) } private val builder by lazy { PreferenceGraphProto.newBuilder() } - private val visitedScreens = mutableSetOf<String>().apply { addAll(request.visitedScreens) } + private val visitedScreens = request.visitedScreens.toMutableSet() + private val screens = mutableMapOf<String, PreferenceScreenProto.Builder>() private suspend fun init() { - for (key in request.screenKeys) { - addPreferenceScreenFromRegistry(key) + for (screen in request.screens) { + PreferenceScreenRegistry.create(context, screen)?.let { addPreferenceScreen(it) } } } - fun build(): PreferenceGraphProto = builder.build() + fun build(): PreferenceGraphProto { + for ((key, screenBuilder) in screens) builder.putScreens(key, screenBuilder.build()) + return builder.build() + } /** * Adds an activity to the graph. @@ -138,19 +146,12 @@ private constructor( null } - suspend fun addPreferenceScreenFromRegistry(key: String): Boolean { - val metadata = PreferenceScreenRegistry.create(context, key) ?: return false - return addPreferenceScreenMetadata(metadata) + private suspend fun addPreferenceScreenFromRegistry(key: String): Boolean { + val factory = + PreferenceScreenRegistry.preferenceScreenMetadataFactories[key] ?: return false + return addPreferenceScreen(factory) } - private suspend fun addPreferenceScreenMetadata(metadata: PreferenceScreenMetadata): Boolean = - addPreferenceScreen(metadata.key) { - preferenceScreenProto { - completeHierarchy = metadata.hasCompleteHierarchy() - root = metadata.getPreferenceHierarchy(context).toProto(metadata, true) - } - } - suspend fun addPreferenceScreenProvider(activityClass: Class<*>) { Log.d(TAG, "add $activityClass") createPreferenceScreen { activityClass.newInstance() } @@ -188,26 +189,52 @@ private constructor( Log.e(TAG, "\"$preferenceScreen\" has no key") return } - @Suppress("CheckReturnValue") addPreferenceScreen(key) { preferenceScreen.toProto(intent) } + val args = preferenceScreen.peekExtras()?.getBundle(EXTRA_BINDING_SCREEN_ARGS) + @Suppress("CheckReturnValue") + addPreferenceScreen(key, args) { + this.intent = intent.toProto() + root = preferenceScreen.toProto() + } + } + + suspend fun addPreferenceScreen(factory: PreferenceScreenMetadataFactory): Boolean { + if (factory is PreferenceScreenMetadataParameterizedFactory) { + factory.parameters(context).collect { addPreferenceScreen(factory.create(context, it)) } + return true + } + return addPreferenceScreen(factory.create(context)) } + private suspend fun addPreferenceScreen(metadata: PreferenceScreenMetadata): Boolean = + addPreferenceScreen(metadata.key, metadata.arguments) { + completeHierarchy = metadata.hasCompleteHierarchy() + root = metadata.getPreferenceHierarchy(context).toProto(metadata, true) + } + private suspend fun addPreferenceScreen( key: String, - preferenceScreenProvider: suspend () -> PreferenceScreenProto, - ): Boolean = - if (visitedScreens.add(key)) { - builder.putScreens(key, preferenceScreenProvider()) - true - } else { - Log.w(TAG, "$key visited") - false + args: Bundle?, + init: suspend PreferenceScreenProto.Builder.() -> Unit, + ): Boolean { + if (!visitedScreens.add(PreferenceScreenCoordinate(key, args))) { + Log.w(TAG, "$key $args visited") + return false } - - private suspend fun PreferenceScreen.toProto(intent: Intent?): PreferenceScreenProto = - preferenceScreenProto { - intent?.let { this.intent = it.toProto() } - root = (this@toProto as PreferenceGroup).toProto() + if (args == null) { // normal screen + screens[key] = PreferenceScreenProto.newBuilder().also { init(it) } + } else if (args.isEmpty) { // parameterized screen with backward compatibility + val builder = screens.getOrPut(key) { PreferenceScreenProto.newBuilder() } + init(builder) + } else { // parameterized screen with non-empty arguments + val builder = screens.getOrPut(key) { PreferenceScreenProto.newBuilder() } + val parameterizedScreen = parameterizedPreferenceScreenProto { + setArgs(args.toProto()) + setScreen(PreferenceScreenProto.newBuilder().also { init(it) }) + } + builder.addParameterizedScreens(parameterizedScreen) } + return true + } private suspend fun PreferenceGroup.toProto(): PreferenceGroupProto = preferenceGroupProto { preference = (this@toProto as Preference).toProto() @@ -271,7 +298,7 @@ private constructor( .toProto(context, callingPid, callingUid, screenMetadata, isRoot, request.flags) .also { if (metadata is PreferenceScreenMetadata) { - @Suppress("CheckReturnValue") addPreferenceScreenMetadata(metadata) + @Suppress("CheckReturnValue") addPreferenceScreen(metadata) } metadata.intent(context)?.resolveActivity(context.packageManager)?.let { if (it.packageName == context.packageName) { @@ -322,7 +349,7 @@ private constructor( val screenKey = screen?.key if (!screenKey.isNullOrEmpty()) { @Suppress("CheckReturnValue") - addPreferenceScreen(screenKey) { screen.toProto(null) } + addPreferenceScreen(screenKey, null) { root = screen.toProto() } return actionTargetProto { key = screenKey } } } catch (e: Exception) { diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt index 728055c2f837..60f9c6bb92a3 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt @@ -19,6 +19,7 @@ package com.android.settingslib.graph import android.app.Application import android.content.Context import android.os.Bundle +import android.os.SystemClock import androidx.annotation.IntDef import com.android.settingslib.graph.proto.PreferenceValueProto import com.android.settingslib.ipc.ApiDescriptor @@ -29,7 +30,9 @@ import com.android.settingslib.ipc.MessageCodec import com.android.settingslib.metadata.IntRangeValuePreference import com.android.settingslib.metadata.PersistentPreference import com.android.settingslib.metadata.PreferenceAvailabilityProvider +import com.android.settingslib.metadata.PreferenceCoordinate import com.android.settingslib.metadata.PreferenceMetadata +import com.android.settingslib.metadata.PreferenceRemoteOpMetricsLogger import com.android.settingslib.metadata.PreferenceRestrictionProvider import com.android.settingslib.metadata.PreferenceScreenRegistry import com.android.settingslib.metadata.ReadWritePermit @@ -37,11 +40,12 @@ import com.android.settingslib.metadata.SensitivityLevel.Companion.HIGH_SENSITIV import com.android.settingslib.metadata.SensitivityLevel.Companion.UNKNOWN_SENSITIVITY /** Request to set preference value. */ -data class PreferenceSetterRequest( - val screenKey: String, - val key: String, +class PreferenceSetterRequest( + screenKey: String, + args: Bundle?, + key: String, val value: PreferenceValueProto, -) +) : PreferenceCoordinate(screenKey, args, key) /** Result of preference setter request. */ @IntDef( @@ -97,6 +101,7 @@ class PreferenceSetterApiDescriptor(override val id: Int) : class PreferenceSetterApiHandler( override val id: Int, private val permissionChecker: ApiPermissionChecker<PreferenceSetterRequest>, + private val metricsLogger: PreferenceRemoteOpMetricsLogger? = null, ) : ApiHandler<PreferenceSetterRequest, Int> { override fun hasPermission( @@ -112,21 +117,24 @@ class PreferenceSetterApiHandler( callingUid: Int, request: PreferenceSetterRequest, ): Int { + val elapsedRealtime = SystemClock.elapsedRealtime() + fun notFound(): Int { + metricsLogger?.logSetterApi( + application, + callingUid, + request, + null, + null, + PreferenceSetterResult.UNSUPPORTED, + SystemClock.elapsedRealtime() - elapsedRealtime, + ) + return PreferenceSetterResult.UNSUPPORTED + } val screenMetadata = - PreferenceScreenRegistry.create(application, request.screenKey) - ?: return PreferenceSetterResult.UNSUPPORTED + PreferenceScreenRegistry.create(application, request) ?: return notFound() val key = request.key val metadata = - screenMetadata.getPreferenceHierarchy(application).find(key) - ?: return PreferenceSetterResult.UNSUPPORTED - if (metadata !is PersistentPreference<*>) return PreferenceSetterResult.UNSUPPORTED - if (!metadata.isEnabled(application)) return PreferenceSetterResult.DISABLED - if (metadata is PreferenceRestrictionProvider && metadata.isRestricted(application)) { - return PreferenceSetterResult.RESTRICTED - } - if (metadata is PreferenceAvailabilityProvider && !metadata.isAvailable(application)) { - return PreferenceSetterResult.UNAVAILABLE - } + screenMetadata.getPreferenceHierarchy(application).find(key) ?: return notFound() fun <T> PreferenceMetadata.checkWritePermit(value: T): Int { @Suppress("UNCHECKED_CAST") val preference = (this as PersistentPreference<T>) @@ -141,41 +149,64 @@ class PreferenceSetterApiHandler( } } - val storage = metadata.storage(application) - val value = request.value - try { - if (value.hasBooleanValue()) { - if (metadata.valueType != Boolean::class.javaObjectType) { - return PreferenceSetterResult.INVALID_REQUEST - } - val booleanValue = value.booleanValue - val resultCode = metadata.checkWritePermit(booleanValue) - if (resultCode != PreferenceSetterResult.OK) return resultCode - storage.setBoolean(key, booleanValue) - return PreferenceSetterResult.OK - } else if (value.hasIntValue()) { - val intValue = value.intValue - val resultCode = metadata.checkWritePermit(intValue) - if (resultCode != PreferenceSetterResult.OK) return resultCode - if ( - metadata is IntRangeValuePreference && - !metadata.isValidValue(application, intValue) - ) { - return PreferenceSetterResult.INVALID_REQUEST + fun invoke(): Int { + if (metadata !is PersistentPreference<*>) return PreferenceSetterResult.UNSUPPORTED + if (!metadata.isEnabled(application)) return PreferenceSetterResult.DISABLED + if (metadata is PreferenceRestrictionProvider && metadata.isRestricted(application)) { + return PreferenceSetterResult.RESTRICTED + } + if (metadata is PreferenceAvailabilityProvider && !metadata.isAvailable(application)) { + return PreferenceSetterResult.UNAVAILABLE + } + + val storage = metadata.storage(application) + val value = request.value + try { + if (value.hasBooleanValue()) { + if (metadata.valueType != Boolean::class.javaObjectType) { + return PreferenceSetterResult.INVALID_REQUEST + } + val booleanValue = value.booleanValue + val resultCode = metadata.checkWritePermit(booleanValue) + if (resultCode != PreferenceSetterResult.OK) return resultCode + storage.setBoolean(key, booleanValue) + return PreferenceSetterResult.OK + } else if (value.hasIntValue()) { + val intValue = value.intValue + val resultCode = metadata.checkWritePermit(intValue) + if (resultCode != PreferenceSetterResult.OK) return resultCode + if ( + metadata is IntRangeValuePreference && + !metadata.isValidValue(application, intValue) + ) { + return PreferenceSetterResult.INVALID_REQUEST + } + storage.setInt(key, intValue) + return PreferenceSetterResult.OK + } else if (value.hasFloatValue()) { + val floatValue = value.floatValue + val resultCode = metadata.checkWritePermit(floatValue) + if (resultCode != PreferenceSetterResult.OK) return resultCode + storage.setFloat(key, floatValue) + return PreferenceSetterResult.OK } - storage.setInt(key, intValue) - return PreferenceSetterResult.OK - } else if (value.hasFloatValue()) { - val floatValue = value.floatValue - val resultCode = metadata.checkWritePermit(floatValue) - if (resultCode != PreferenceSetterResult.OK) return resultCode - storage.setFloat(key, floatValue) - return PreferenceSetterResult.OK + } catch (e: Exception) { + return PreferenceSetterResult.INTERNAL_ERROR } - } catch (e: Exception) { - return PreferenceSetterResult.INTERNAL_ERROR + return PreferenceSetterResult.INVALID_REQUEST } - return PreferenceSetterResult.INVALID_REQUEST + + val result = invoke() + metricsLogger?.logSetterApi( + application, + callingUid, + request, + screenMetadata, + metadata, + result, + SystemClock.elapsedRealtime() - elapsedRealtime, + ) + return result } override val requestCodec: MessageCodec<PreferenceSetterRequest> @@ -205,6 +236,7 @@ object PreferenceSetterRequestCodec : MessageCodec<PreferenceSetterRequest> { override fun encode(data: PreferenceSetterRequest) = Bundle(3).apply { putString(SCREEN_KEY, data.screenKey) + putBundle(ARGS, data.args) putString(KEY, data.key) putByteArray(null, data.value.toByteArray()) } @@ -212,10 +244,12 @@ object PreferenceSetterRequestCodec : MessageCodec<PreferenceSetterRequest> { override fun decode(data: Bundle) = PreferenceSetterRequest( data.getString(SCREEN_KEY)!!, + data.getBundle(ARGS), data.getString(KEY)!!, PreferenceValueProto.parseFrom(data.getByteArray(null)!!), ) private const val SCREEN_KEY = "s" private const val KEY = "k" + private const val ARGS = "a" } diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt index adbe77318353..5f2a0d826407 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt @@ -19,6 +19,7 @@ package com.android.settingslib.graph import com.android.settingslib.graph.proto.BundleProto import com.android.settingslib.graph.proto.BundleProto.BundleValue import com.android.settingslib.graph.proto.IntentProto +import com.android.settingslib.graph.proto.ParameterizedPreferenceScreenProto import com.android.settingslib.graph.proto.PreferenceGroupProto import com.android.settingslib.graph.proto.PreferenceOrGroupProto import com.android.settingslib.graph.proto.PreferenceProto @@ -39,6 +40,12 @@ inline fun preferenceScreenProto( init: PreferenceScreenProto.Builder.() -> Unit ): PreferenceScreenProto = PreferenceScreenProto.newBuilder().also(init).build() +/** Kotlin DSL-style builder for [PreferenceScreenProto]. */ +inline fun parameterizedPreferenceScreenProto( + init: ParameterizedPreferenceScreenProto.Builder.() -> Unit +): ParameterizedPreferenceScreenProto = + ParameterizedPreferenceScreenProto.newBuilder().also(init).build() + /** Returns preference or null. */ val PreferenceOrGroupProto.preferenceOrNull get() = if (hasPreference()) preference else null diff --git a/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml b/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml index 43cf6aa09109..7adcbf6c6601 100644 --- a/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml +++ b/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml @@ -18,6 +18,8 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/entity_header" + android:layout_width="match_parent" + android:layout_height="wrap_content" style="@style/SettingsLibEntityHeader"> <LinearLayout diff --git a/packages/SettingsLib/Metadata/processor/src/com/android/settingslib/metadata/PreferenceScreenAnnotationProcessor.kt b/packages/SettingsLib/Metadata/processor/src/com/android/settingslib/metadata/PreferenceScreenAnnotationProcessor.kt index 38b641336547..69b75adea9d3 100644 --- a/packages/SettingsLib/Metadata/processor/src/com/android/settingslib/metadata/PreferenceScreenAnnotationProcessor.kt +++ b/packages/SettingsLib/Metadata/processor/src/com/android/settingslib/metadata/PreferenceScreenAnnotationProcessor.kt @@ -33,6 +33,9 @@ import javax.tools.Diagnostic /** Processor to gather preference screens annotated with `@ProvidePreferenceScreen`. */ class PreferenceScreenAnnotationProcessor : AbstractProcessor() { private val screens = mutableListOf<Screen>() + private val bundleType: TypeMirror by lazy { + processingEnv.elementUtils.getTypeElement("android.os.Bundle").asType() + } private val contextType: TypeMirror by lazy { processingEnv.elementUtils.getTypeElement("android.content.Context").asType() } @@ -83,19 +86,57 @@ class PreferenceScreenAnnotationProcessor : AbstractProcessor() { error("@$ANNOTATION_NAME must be added to $PREFERENCE_SCREEN_METADATA subclass", this) return } - val constructorType = getConstructorType() - if (constructorType == null) { + fun reportConstructorError() = error( - "Class must be an object, or has single public constructor that " + - "accepts no parameter or a Context parameter", + "Must have only one public constructor: constructor(), " + + "constructor(Context), constructor(Bundle) or constructor(Context, Bundle)", this, ) + val constructor = findConstructor() + if (constructor == null || constructor.parameters.size > 2) { + reportConstructorError() return } + val constructorHasContextParameter = constructor.hasParameter(0, contextType) + var index = if (constructorHasContextParameter) 1 else 0 val annotation = annotationMirrors.single { it.isElement(annotationElement) } val key = annotation.fieldValue<String>("value")!! val overlay = annotation.fieldValue<Boolean>("overlay") == true - screens.add(Screen(key, overlay, qualifiedName.toString(), constructorType)) + val parameterized = annotation.fieldValue<Boolean>("parameterized") == true + var parametersHasContextParameter = false + if (parameterized) { + val parameters = findParameters() + if (parameters == null) { + error("require a static 'parameters()' or 'parameters(Context)' method", this) + return + } + parametersHasContextParameter = parameters + if (constructor.hasParameter(index, bundleType)) { + index++ + } else { + error( + "Parameterized screen constructor must be" + + "constructor(Bundle) or constructor(Context, Bundle)", + this, + ) + return + } + } + if (index == constructor.parameters.size) { + screens.add( + Screen( + key, + overlay, + parameterized, + annotation.fieldValue<Boolean>("parameterizedMigration") == true, + qualifiedName.toString(), + constructorHasContextParameter, + parametersHasContextParameter, + ) + ) + } else { + reportConstructorError() + } } private fun codegen() { @@ -116,10 +157,15 @@ class PreferenceScreenAnnotationProcessor : AbstractProcessor() { screens.sort() processingEnv.filer.createSourceFile("$outputPkg.$outputClass").openWriter().use { it.write("package $outputPkg;\n\n") + it.write("import android.content.Context;\n") + it.write("import android.os.Bundle;\n") it.write("import $PACKAGE.FixedArrayMap;\n") it.write("import $PACKAGE.FixedArrayMap.OrderedInitializer;\n") - it.write("import $PACKAGE.$FACTORY;\n\n") - it.write("// Generated by annotation processor for @$ANNOTATION_NAME\n") + it.write("import $PACKAGE.$PREFERENCE_SCREEN_METADATA;\n") + it.write("import $PACKAGE.$FACTORY;\n") + it.write("import $PACKAGE.$PARAMETERIZED_FACTORY;\n") + it.write("import kotlinx.coroutines.flow.Flow;\n") + it.write("\n// Generated by annotation processor for @$ANNOTATION_NAME\n") it.write("public final class $outputClass {\n") it.write(" private $outputClass() {}\n\n") it.write(" public static FixedArrayMap<String, $FACTORY> $outputFun() {\n") @@ -127,10 +173,29 @@ class PreferenceScreenAnnotationProcessor : AbstractProcessor() { it.write(" return new FixedArrayMap<>($size, $outputClass::init);\n") it.write(" }\n\n") fun Screen.write() { - it.write(" screens.put(\"$key\", context -> new $klass(") - when (constructorType) { - ConstructorType.DEFAULT -> it.write("));") - ConstructorType.CONTEXT -> it.write("context));") + it.write(" screens.put(\"$key\", ") + if (parameterized) { + it.write("new $PARAMETERIZED_FACTORY() {\n") + it.write(" @Override public PreferenceScreenMetadata create") + it.write("(Context context, Bundle args) {\n") + it.write(" return new $klass(") + if (constructorHasContextParameter) it.write("context, ") + it.write("args);\n") + it.write(" }\n\n") + it.write(" @Override public Flow<Bundle> parameters(Context context) {\n") + it.write(" return $klass.parameters(") + if (parametersHasContextParameter) it.write("context") + it.write(");\n") + it.write(" }\n") + if (parameterizedMigration) { + it.write("\n @Override public boolean acceptEmptyArguments()") + it.write(" { return true; }\n") + } + it.write(" });") + } else { + it.write("context -> new $klass(") + if (constructorHasContextParameter) it.write("context") + it.write("));") } if (overlay) it.write(" // overlay") it.write("\n") @@ -159,7 +224,7 @@ class PreferenceScreenAnnotationProcessor : AbstractProcessor() { } private fun AnnotationMirror.isElement(element: TypeElement) = - processingEnv.typeUtils.isSameType(annotationType.asElement().asType(), element.asType()) + annotationType.asElement().asType().isSameType(element.asType()) @Suppress("UNCHECKED_CAST") private fun <T> AnnotationMirror.fieldValue(name: String): T? = field(name)?.value as? T @@ -171,7 +236,7 @@ class PreferenceScreenAnnotationProcessor : AbstractProcessor() { return null } - private fun TypeElement.getConstructorType(): ConstructorType? { + private fun TypeElement.findConstructor(): ExecutableElement? { var constructor: ExecutableElement? = null for (element in enclosedElements) { if (element.kind != ElementKind.CONSTRUCTOR) continue @@ -179,16 +244,30 @@ class PreferenceScreenAnnotationProcessor : AbstractProcessor() { if (constructor != null) return null constructor = element as ExecutableElement } - return constructor?.parameters?.run { - when { - isEmpty() -> ConstructorType.DEFAULT - size == 1 && processingEnv.typeUtils.isSameType(this[0].asType(), contextType) -> - ConstructorType.CONTEXT - else -> null - } + return constructor + } + + private fun TypeElement.findParameters(): Boolean? { + for (element in enclosedElements) { + if (element.kind != ElementKind.METHOD) continue + if (!element.modifiers.contains(Modifier.PUBLIC)) continue + if (!element.modifiers.contains(Modifier.STATIC)) continue + if (!element.simpleName.contentEquals("parameters")) return null + val parameters = (element as ExecutableElement).parameters + if (parameters.isEmpty()) return false + if (parameters.size == 1 && parameters[0].asType().isSameType(contextType)) return true + error("parameters method should have no parameter or a Context parameter", element) + return null } + return null } + private fun ExecutableElement.hasParameter(index: Int, typeMirror: TypeMirror) = + index < parameters.size && parameters[index].asType().isSameType(typeMirror) + + private fun TypeMirror.isSameType(typeMirror: TypeMirror) = + processingEnv.typeUtils.isSameType(this, typeMirror) + private fun warn(msg: CharSequence) = processingEnv.messager.printMessage(Diagnostic.Kind.WARNING, msg) @@ -198,8 +277,11 @@ class PreferenceScreenAnnotationProcessor : AbstractProcessor() { private data class Screen( val key: String, val overlay: Boolean, + val parameterized: Boolean, + val parameterizedMigration: Boolean, val klass: String, - val constructorType: ConstructorType, + val constructorHasContextParameter: Boolean, + val parametersHasContextParameter: Boolean, ) : Comparable<Screen> { override fun compareTo(other: Screen): Int { val diff = key.compareTo(other.key) @@ -207,17 +289,13 @@ class PreferenceScreenAnnotationProcessor : AbstractProcessor() { } } - private enum class ConstructorType { - DEFAULT, // default constructor with no parameter - CONTEXT, // constructor with a Context parameter - } - companion object { private const val PACKAGE = "com.android.settingslib.metadata" private const val ANNOTATION_NAME = "ProvidePreferenceScreen" private const val ANNOTATION = "$PACKAGE.$ANNOTATION_NAME" private const val PREFERENCE_SCREEN_METADATA = "PreferenceScreenMetadata" private const val FACTORY = "PreferenceScreenMetadataFactory" + private const val PARAMETERIZED_FACTORY = "PreferenceScreenMetadataParameterizedFactory" private const val OPTIONS_NAME = "ProvidePreferenceScreenOptions" private const val OPTIONS = "$PACKAGE.$OPTIONS_NAME" diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/Annotations.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/Annotations.kt index 4bed795ea760..449c78ce8965 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/Annotations.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/Annotations.kt @@ -22,14 +22,27 @@ package com.android.settingslib.metadata * The annotated class must satisfy either condition: * - the primary constructor has no parameter * - the primary constructor has a single [android.content.Context] parameter + * - (parameterized) the primary constructor has a single [android.os.Bundle] parameter to override + * [PreferenceScreenMetadata.arguments] + * - (parameterized) the primary constructor has a [android.content.Context] and a + * [android.os.Bundle] parameter to override [PreferenceScreenMetadata.arguments] * * @param value unique preference screen key * @param overlay if true, current annotated screen will overlay the screen that has identical key + * @param parameterized if true, the screen relies on additional arguments to build its content + * @param parameterizedMigration whether the parameterized screen was a normal screen, in which case + * `Bundle.EMPTY` will be passed as arguments to take care of backward compatibility + * @see PreferenceScreenMetadata */ @Retention(AnnotationRetention.SOURCE) @Target(AnnotationTarget.CLASS) @MustBeDocumented -annotation class ProvidePreferenceScreen(val value: String, val overlay: Boolean = false) +annotation class ProvidePreferenceScreen( + val value: String, + val overlay: Boolean = false, + val parameterized: Boolean = false, + val parameterizedMigration: Boolean = false, // effective only when parameterized is true +) /** * Provides options for [ProvidePreferenceScreen] annotation processor. diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/Bundles.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/Bundles.kt new file mode 100644 index 000000000000..a63576510aec --- /dev/null +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/Bundles.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.metadata + +import android.content.Intent +import android.os.Bundle + +@Suppress("DEPRECATION") +fun Bundle?.contentEquals(other: Bundle?): Boolean { + if (this == null) return other == null + if (other == null) return false + if (keySet() != other.keySet()) return false + fun Any?.valueEquals(other: Any?) = + when (this) { + is Bundle -> other is Bundle && this.contentEquals(other) + is Intent -> other is Intent && this.filterEquals(other) + is BooleanArray -> other is BooleanArray && this contentEquals other + is ByteArray -> other is ByteArray && this contentEquals other + is CharArray -> other is CharArray && this contentEquals other + is DoubleArray -> other is DoubleArray && this contentEquals other + is FloatArray -> other is FloatArray && this contentEquals other + is IntArray -> other is IntArray && this contentEquals other + is LongArray -> other is LongArray && this contentEquals other + is ShortArray -> other is ShortArray && this contentEquals other + is Array<*> -> other is Array<*> && this contentDeepEquals other + else -> this == other + } + for (key in keySet()) { + if (!get(key).valueEquals(other.get(key))) return false + } + return true +} diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/Metrics.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/Metrics.kt index 7323488c5299..e532e545cc11 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/Metrics.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/Metrics.kt @@ -16,6 +16,8 @@ package com.android.settingslib.metadata +import android.content.Context + /** Metrics logger for preference actions triggered by user interaction. */ interface PreferenceUiActionMetricsLogger { @@ -28,8 +30,34 @@ interface PreferenceUiActionMetricsLogger { screen: PreferenceScreenMetadata, preference: PreferenceMetadata, value: Any?, - ) {} + ) } /** Metrics logger for preference remote operations (e.g. external get/set). */ -interface PreferenceRemoteOpMetricsLogger +interface PreferenceRemoteOpMetricsLogger { + + /** Logs get preference metadata operation. */ + fun logGetterApi( + context: Context, + callingUid: Int, + preferenceCoordinate: PreferenceCoordinate, + screen: PreferenceScreenMetadata?, + preference: PreferenceMetadata?, + errorCode: Int, + latencyMs: Long, + ) + + /** Logs set preference value operation. */ + fun logSetterApi( + context: Context, + callingUid: Int, + preferenceCoordinate: PreferenceCoordinate, + screen: PreferenceScreenMetadata?, + preference: PreferenceMetadata?, + errorCode: Int, + latencyMs: Long, + ) + + /** Logs get preference graph operation. */ + fun logGraphApi(context: Context, callingUid: Int, success: Boolean, latencyMs: Long) +} diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt index 63f1050df94e..e456a7f1aa1c 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PersistentPreference.kt @@ -78,13 +78,8 @@ annotation class SensitivityLevel { /** Preference metadata that has a value persisted in datastore. */ interface PersistentPreference<T> : PreferenceMetadata { - /** - * The value type the preference is associated with. - * - * TODO(b/388167302): Remove the default implementation once all subclasses are migrated. - */ - val valueType: Class<T>? - get() = null + /** The value type the preference is associated with. */ + val valueType: Class<T> /** * Returns the key-value storage of the preference. diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceCoordinate.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceCoordinate.kt index 2dd736ae6083..ac08847b6002 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceCoordinate.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceCoordinate.kt @@ -16,26 +16,41 @@ package com.android.settingslib.metadata +import android.os.Bundle import android.os.Parcel import android.os.Parcelable /** * Coordinate to locate a preference. * - * Within an app, the preference screen key (unique among screens) plus preference key (unique on - * the screen) is used to locate a preference. + * Within an app, the preference screen coordinate (unique among screens) plus preference key + * (unique on the screen) is used to locate a preference. */ -data class PreferenceCoordinate(val screenKey: String, val key: String) : Parcelable { +open class PreferenceCoordinate : PreferenceScreenCoordinate { + val key: String - constructor(parcel: Parcel) : this(parcel.readString()!!, parcel.readString()!!) + constructor(screenKey: String, key: String) : this(screenKey, null, key) + + constructor(screenKey: String, args: Bundle?, key: String) : super(screenKey, args) { + this.key = key + } + + constructor(parcel: Parcel) : super(parcel) { + this.key = parcel.readString()!! + } override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeString(screenKey) + super.writeToParcel(parcel, flags) parcel.writeString(key) } override fun describeContents() = 0 + override fun equals(other: Any?) = + super.equals(other) && key == (other as PreferenceCoordinate).key + + override fun hashCode() = super.hashCode() xor key.hashCode() + companion object CREATOR : Parcelable.Creator<PreferenceCoordinate> { override fun createFromParcel(parcel: Parcel) = PreferenceCoordinate(parcel) @@ -43,3 +58,46 @@ data class PreferenceCoordinate(val screenKey: String, val key: String) : Parcel override fun newArray(size: Int) = arrayOfNulls<PreferenceCoordinate>(size) } } + +/** Coordinate to locate a preference screen. */ +open class PreferenceScreenCoordinate : Parcelable { + /** Unique preference screen key. */ + val screenKey: String + + /** Arguments to create parameterized preference screen. */ + val args: Bundle? + + constructor(screenKey: String, args: Bundle?) { + this.screenKey = screenKey + this.args = args + } + + constructor(parcel: Parcel) { + screenKey = parcel.readString()!! + args = parcel.readBundle(javaClass.classLoader) + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(screenKey) + parcel.writeBundle(args) + } + + override fun describeContents() = 0 + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + other as PreferenceScreenCoordinate + return screenKey == other.screenKey && args.contentEquals(other.args) + } + + // "args" is not included intentionally, otherwise we need to take care of array, etc. + override fun hashCode() = screenKey.hashCode() + + companion object CREATOR : Parcelable.Creator<PreferenceScreenCoordinate> { + + override fun createFromParcel(parcel: Parcel) = PreferenceScreenCoordinate(parcel) + + override fun newArray(size: Int) = arrayOfNulls<PreferenceScreenCoordinate>(size) + } +} diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt index 876f6152cccd..3bd051dee41d 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt @@ -17,6 +17,7 @@ package com.android.settingslib.metadata import android.content.Context +import android.os.Bundle /** A node in preference hierarchy that is associated with [PreferenceMetadata]. */ open class PreferenceHierarchyNode internal constructor(val metadata: PreferenceMetadata) { @@ -54,8 +55,14 @@ internal constructor(private val context: Context, metadata: PreferenceMetadata) * * @throws NullPointerException if screen is not registered to [PreferenceScreenRegistry] */ - operator fun String.unaryPlus() = - +PreferenceHierarchyNode(PreferenceScreenRegistry.create(context, this)!!) + operator fun String.unaryPlus() = addPreferenceScreen(this, null) + + /** + * Adds parameterized preference screen with given key (as a placeholder) to the hierarchy. + * + * @see String.unaryPlus + */ + infix fun String.args(args: Bundle) = createPreferenceScreenHierarchy(this, args) operator fun PreferenceHierarchyNode.unaryPlus() = also { children.add(it) } @@ -122,6 +129,14 @@ internal constructor(private val context: Context, metadata: PreferenceMetadata) } /** + * Adds parameterized preference screen with given key (as a placeholder) to the hierarchy. + * + * @see addPreferenceScreen + */ + fun addParameterizedScreen(screenKey: String, args: Bundle) = + addPreferenceScreen(screenKey, args) + + /** * Adds preference screen with given key (as a placeholder) to the hierarchy. * * This is mainly to support Android Settings overlays. OEMs might want to custom some of the @@ -132,11 +147,13 @@ internal constructor(private val context: Context, metadata: PreferenceMetadata) * * @throws NullPointerException if screen is not registered to [PreferenceScreenRegistry] */ - fun addPreferenceScreen(screenKey: String) { - children.add( - PreferenceHierarchy(context, PreferenceScreenRegistry.create(context, screenKey)!!) - ) - } + fun addPreferenceScreen(screenKey: String) = addPreferenceScreen(screenKey, null) + + private fun addPreferenceScreen(screenKey: String, args: Bundle?): PreferenceHierarchyNode = + createPreferenceScreenHierarchy(screenKey, args).also { children.add(it) } + + private fun createPreferenceScreenHierarchy(screenKey: String, args: Bundle?) = + PreferenceHierarchyNode(PreferenceScreenRegistry.create(context, screenKey, args)!!) /** Extensions to add more preferences to the hierarchy. */ operator fun PreferenceHierarchy.plusAssign(init: PreferenceHierarchy.() -> Unit) = init(this) diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenBindingKeyProvider.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenBindingKeyProvider.kt index 84014f191f68..4fd13ede6803 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenBindingKeyProvider.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenBindingKeyProvider.kt @@ -17,13 +17,20 @@ package com.android.settingslib.metadata import android.content.Context +import android.os.Bundle /** Provides the associated preference screen key for binding. */ interface PreferenceScreenBindingKeyProvider { /** Returns the associated preference screen key. */ fun getPreferenceScreenBindingKey(context: Context): String? + + /** Returns the arguments to build preference screen. */ + fun getPreferenceScreenBindingArgs(context: Context): Bundle? } /** Extra key to provide the preference screen key for binding. */ const val EXTRA_BINDING_SCREEN_KEY = "settingslib:binding_screen_key" + +/** Extra key to provide arguments for preference screen binding. */ +const val EXTRA_BINDING_SCREEN_ARGS = "settingslib:binding_screen_args" diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenMetadata.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenMetadata.kt index 850d4523e96e..7f1ded71e30a 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenMetadata.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenMetadata.kt @@ -18,12 +18,25 @@ package com.android.settingslib.metadata import android.content.Context import android.content.Intent +import android.os.Bundle import androidx.annotation.AnyThread import androidx.fragment.app.Fragment +import kotlinx.coroutines.flow.Flow -/** Metadata of preference screen. */ +/** + * Metadata of preference screen. + * + * For parameterized preference screen that relies on additional information (e.g. package name, + * language code) to build its content, the subclass must: + * - override [arguments] in constructor + * - add a static method `fun parameters(context: Context): List<Bundle>` (context is optional) to + * provide all possible arguments + */ @AnyThread interface PreferenceScreenMetadata : PreferenceMetadata { + /** Arguments to build the screen content. */ + val arguments: Bundle? + get() = null /** * The screen title resource, which precedes [getScreenTitle] if provided. @@ -65,7 +78,12 @@ interface PreferenceScreenMetadata : PreferenceMetadata { fun getLaunchIntent(context: Context, metadata: PreferenceMetadata?): Intent? = null } -/** Factory of [PreferenceScreenMetadata]. */ +/** + * Factory of [PreferenceScreenMetadata]. + * + * Annotation processor generates implementation of this interface based on + * [ProvidePreferenceScreen] when [ProvidePreferenceScreen.parameterized] is `false`. + */ fun interface PreferenceScreenMetadataFactory { /** @@ -75,3 +93,44 @@ fun interface PreferenceScreenMetadataFactory { */ fun create(context: Context): PreferenceScreenMetadata } + +/** + * Parameterized factory of [PreferenceScreenMetadata]. + * + * Annotation processor generates implementation of this interface based on + * [ProvidePreferenceScreen] when [ProvidePreferenceScreen.parameterized] is `true`. + */ +interface PreferenceScreenMetadataParameterizedFactory : PreferenceScreenMetadataFactory { + override fun create(context: Context) = create(context, Bundle.EMPTY) + + /** + * Creates a new [PreferenceScreenMetadata] with given arguments. + * + * @param context application context to create the PreferenceScreenMetadata + * @param args arguments to create the screen metadata, [Bundle.EMPTY] is reserved for the + * default case when screen is migrated from normal to parameterized + */ + fun create(context: Context, args: Bundle): PreferenceScreenMetadata + + /** + * Returns all possible arguments to create [PreferenceScreenMetadata]. + * + * Note that [Bundle.EMPTY] is a special arguments reserved for backward compatibility when a + * preference screen was a normal screen but migrated to parameterized screen later: + * 1. Set [ProvidePreferenceScreen.parameterizedMigration] to `true`, so that the generated + * [acceptEmptyArguments] will be `true`. + * 1. In the original [parameters] implementation, produce a [Bundle.EMPTY] for the default + * case. + * + * Do not use [Bundle.EMPTY] for other purpose. + */ + fun parameters(context: Context): Flow<Bundle> + + /** + * Returns true when the parameterized screen was a normal screen. + * + * The [PreferenceScreenMetadata] is expected to accept an empty arguments ([Bundle.EMPTY]) and + * take care of backward compatibility. + */ + fun acceptEmptyArguments(): Boolean = false +} diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenRegistry.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenRegistry.kt index c74b3151abb2..246310984db9 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenRegistry.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceScreenRegistry.kt @@ -17,10 +17,13 @@ package com.android.settingslib.metadata import android.content.Context +import android.os.Bundle +import android.util.Log import com.android.settingslib.datastore.KeyValueStore /** Registry of all available preference screens in the app. */ object PreferenceScreenRegistry : ReadWritePermitProvider { + private const val TAG = "ScreenRegistry" /** Provider of key-value store. */ private lateinit var keyValueStoreProvider: KeyValueStoreProvider @@ -52,9 +55,28 @@ object PreferenceScreenRegistry : ReadWritePermitProvider { fun getKeyValueStore(context: Context, preference: PreferenceMetadata): KeyValueStore? = keyValueStoreProvider.getKeyValueStore(context, preference) - /** Creates [PreferenceScreenMetadata] of particular screen key. */ - fun create(context: Context, screenKey: String?): PreferenceScreenMetadata? = - screenKey?.let { preferenceScreenMetadataFactories[it]?.create(context.applicationContext) } + /** Creates [PreferenceScreenMetadata] of particular screen. */ + fun create(context: Context, screenCoordinate: PreferenceScreenCoordinate) = + create(context, screenCoordinate.screenKey, screenCoordinate.args) + + /** Creates [PreferenceScreenMetadata] of particular screen key with given arguments. */ + fun create(context: Context, screenKey: String?, args: Bundle?): PreferenceScreenMetadata? { + if (screenKey == null) return null + val factory = preferenceScreenMetadataFactories[screenKey] ?: return null + val appContext = context.applicationContext + if (factory is PreferenceScreenMetadataParameterizedFactory) { + if (args != null) return factory.create(appContext, args) + // In case the parameterized screen was a normal scree, it is expected to accept + // Bundle.EMPTY arguments and take care of backward compatibility. + if (factory.acceptEmptyArguments()) return factory.create(appContext) + Log.e(TAG, "screen $screenKey is parameterized but args is not provided") + return null + } else { + if (args == null) return factory.create(appContext) + Log.e(TAG, "screen $screenKey is not parameterized but args is provided") + return null + } + } /** * Sets the provider to check read write permit. Read and write requests are denied by default. diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt index 65fbe2b66e77..dbac17d4e8b8 100644 --- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt +++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBindings.kt @@ -22,6 +22,7 @@ import androidx.preference.PreferenceCategory import androidx.preference.PreferenceScreen import androidx.preference.SwitchPreferenceCompat import androidx.preference.TwoStatePreference +import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_ARGS import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_KEY import com.android.settingslib.metadata.PreferenceMetadata import com.android.settingslib.metadata.PreferenceScreenMetadata @@ -35,9 +36,11 @@ interface PreferenceScreenBinding : PreferenceBinding { super.bind(preference, metadata) val context = preference.context val screenMetadata = metadata as PreferenceScreenMetadata + val extras = preference.extras // Pass the preference key to fragment, so that the fragment could find associated // preference screen registered in PreferenceScreenRegistry - preference.extras.putString(EXTRA_BINDING_SCREEN_KEY, preference.key) + extras.putString(EXTRA_BINDING_SCREEN_KEY, preference.key) + screenMetadata.arguments?.let { extras.putBundle(EXTRA_BINDING_SCREEN_ARGS, it) } if (preference is PreferenceScreen) { val screenTitle = screenMetadata.screenTitle preference.title = diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt index ffe181d0c350..02f91c1bb50b 100644 --- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt +++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt @@ -23,6 +23,7 @@ import android.util.Log import androidx.annotation.XmlRes import androidx.lifecycle.Lifecycle import androidx.preference.PreferenceScreen +import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_ARGS import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_KEY import com.android.settingslib.metadata.PreferenceScreenBindingKeyProvider import com.android.settingslib.metadata.PreferenceScreenRegistry @@ -89,13 +90,19 @@ open class PreferenceFragment : @XmlRes protected open fun getPreferenceScreenResId(context: Context): Int = 0 protected fun getPreferenceScreenCreator(context: Context): PreferenceScreenCreator? = - (PreferenceScreenRegistry.create(context, getPreferenceScreenBindingKey(context)) - as? PreferenceScreenCreator) + (PreferenceScreenRegistry.create( + context, + getPreferenceScreenBindingKey(context), + getPreferenceScreenBindingArgs(context), + ) as? PreferenceScreenCreator) ?.run { if (isFlagEnabled(context)) this else null } override fun getPreferenceScreenBindingKey(context: Context): String? = arguments?.getString(EXTRA_BINDING_SCREEN_KEY) + override fun getPreferenceScreenBindingArgs(context: Context): Bundle? = + arguments?.getBundle(EXTRA_BINDING_SCREEN_ARGS) + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) preferenceScreenBindingHelper?.onCreate() diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt index 4a6a589cd3c9..1cb8005ddae0 100644 --- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt +++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt @@ -31,6 +31,7 @@ import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.KeyedDataObservable import com.android.settingslib.datastore.KeyedObservable import com.android.settingslib.datastore.KeyedObserver +import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_ARGS import com.android.settingslib.metadata.PersistentPreference import com.android.settingslib.metadata.PreferenceChangeReason import com.android.settingslib.metadata.PreferenceHierarchy @@ -227,14 +228,16 @@ class PreferenceScreenBindingHelper( /** Updates preference screen that has incomplete hierarchy. */ @JvmStatic fun bind(preferenceScreen: PreferenceScreen) { - PreferenceScreenRegistry.create(preferenceScreen.context, preferenceScreen.key)?.run { + val context = preferenceScreen.context + val args = preferenceScreen.peekExtras()?.getBundle(EXTRA_BINDING_SCREEN_ARGS) + PreferenceScreenRegistry.create(context, preferenceScreen.key, args)?.run { if (!hasCompleteHierarchy()) { val preferenceBindingFactory = (this as? PreferenceScreenCreator)?.preferenceBindingFactory ?: return bindRecursively( preferenceScreen, preferenceBindingFactory, - getPreferenceHierarchy(preferenceScreen.context), + getPreferenceHierarchy(context), ) } } diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenFactory.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenFactory.kt index 211b3bdaea70..88c4fe6bf188 100644 --- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenFactory.kt +++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenFactory.kt @@ -17,10 +17,12 @@ package com.android.settingslib.preference import android.content.Context +import android.os.Bundle import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceManager import androidx.preference.PreferenceScreen +import com.android.settingslib.metadata.EXTRA_BINDING_SCREEN_ARGS import com.android.settingslib.metadata.PreferenceScreenRegistry /** Factory to create preference screen. */ @@ -81,8 +83,12 @@ class PreferenceScreenFactory { * * The screen must be registered in [PreferenceScreenFactory] and provide a complete hierarchy. */ - fun createBindingScreen(context: Context, screenKey: String?): PreferenceScreen? { - val metadata = PreferenceScreenRegistry.create(context, screenKey) ?: return null + fun createBindingScreen( + context: Context, + screenKey: String?, + args: Bundle?, + ): PreferenceScreen? { + val metadata = PreferenceScreenRegistry.create(context, screenKey, args) ?: return null if (metadata is PreferenceScreenCreator && metadata.hasCompleteHierarchy()) { return metadata.createPreferenceScreen(this) } @@ -94,8 +100,9 @@ class PreferenceScreenFactory { @JvmStatic fun createBindingScreen(preference: Preference): PreferenceScreen? { val context = preference.context + val args = preference.peekExtras()?.getBundle(EXTRA_BINDING_SCREEN_ARGS) val preferenceScreenCreator = - (PreferenceScreenRegistry.create(context, preference.key) + (PreferenceScreenRegistry.create(context, preference.key, args) as? PreferenceScreenCreator) ?: return null if (!preferenceScreenCreator.hasCompleteHierarchy()) return null val factory = PreferenceScreenFactory(context) diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt deleted file mode 100644 index ae9642a38778..000000000000 --- a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settingslib.service - -import android.app.Application -import com.android.settingslib.graph.GetPreferenceGraphApiHandler -import com.android.settingslib.graph.GetPreferenceGraphRequest -import com.android.settingslib.ipc.ApiPermissionChecker -import com.android.settingslib.preference.PreferenceScreenProvider - -/** Api to get preference graph. */ -internal class PreferenceGraphApi( - preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>>, - private val permissionChecker: ApiPermissionChecker<GetPreferenceGraphRequest>, -) : GetPreferenceGraphApiHandler(preferenceScreenProviders) { - - override val id: Int - get() = API_GET_PREFERENCE_GRAPH - - override fun hasPermission( - application: Application, - callingPid: Int, - callingUid: Int, - request: GetPreferenceGraphRequest, - ) = permissionChecker.hasPermission(application, callingPid, callingUid, request) -} diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt index 7cb36db856eb..5def592a1afa 100644 --- a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt +++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt @@ -16,6 +16,7 @@ package com.android.settingslib.service +import com.android.settingslib.graph.GetPreferenceGraphApiHandler import com.android.settingslib.graph.GetPreferenceGraphRequest import com.android.settingslib.graph.PreferenceGetterApiHandler import com.android.settingslib.graph.PreferenceGetterRequest @@ -25,6 +26,7 @@ import com.android.settingslib.ipc.ApiHandler import com.android.settingslib.ipc.ApiPermissionChecker import com.android.settingslib.ipc.MessengerService import com.android.settingslib.ipc.PermissionChecker +import com.android.settingslib.metadata.PreferenceRemoteOpMetricsLogger import com.android.settingslib.preference.PreferenceScreenProvider /** @@ -40,16 +42,26 @@ open class PreferenceService( graphPermissionChecker: ApiPermissionChecker<GetPreferenceGraphRequest>? = null, setterPermissionChecker: ApiPermissionChecker<PreferenceSetterRequest>? = null, getterPermissionChecker: ApiPermissionChecker<PreferenceGetterRequest>? = null, + metricsLogger: PreferenceRemoteOpMetricsLogger? = null, vararg apiHandlers: ApiHandler<*, *>, ) : MessengerService( mutableListOf<ApiHandler<*, *>>().apply { - graphPermissionChecker?.let { add(PreferenceGraphApi(preferenceScreenProviders, it)) } + graphPermissionChecker?.let { + add( + GetPreferenceGraphApiHandler( + API_GET_PREFERENCE_GRAPH, + it, + metricsLogger, + preferenceScreenProviders, + ) + ) + } setterPermissionChecker?.let { - add(PreferenceSetterApiHandler(API_PREFERENCE_SETTER, it)) + add(PreferenceSetterApiHandler(API_PREFERENCE_SETTER, it, metricsLogger)) } getterPermissionChecker?.let { - add(PreferenceGetterApiHandler(API_PREFERENCE_GETTER, it)) + add(PreferenceGetterApiHandler(API_PREFERENCE_GETTER, it, metricsLogger)) } addAll(apiHandlers) }, diff --git a/packages/SettingsLib/SettingsTheme/res/values-af/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-af/strings.xml index eb48b4ec2515..5ebeab57b42b 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-af/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-af/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Vou uit"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Vou in"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Maak toe"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-am/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-am/strings.xml index 442819244b25..27dda46b72cf 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-am/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-am/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ዘርጋ"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ሰብስብ"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"አሰናብት"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ar/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ar/strings.xml index e6d4c7b6cd19..522977e596bb 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ar/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ar/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"توسيع"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"تصغير"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"إغلاق"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-as/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-as/strings.xml index 2b5a5c98b98c..094650753503 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-as/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-as/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"বিস্তাৰ কৰক"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"সংকোচন কৰক"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"অগ্ৰাহ্য কৰক"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-az/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-az/strings.xml index c7adee3095f2..4ba23ddb1382 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-az/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-az/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Genişləndirin"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Yığcamlaşdırın"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Qapadın"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-b+sr+Latn/strings.xml index 8b245a63cd91..02e1e3a1eca1 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-b+sr+Latn/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Proširi"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Skupi"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Odbacite"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-be/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-be/strings.xml index b468f819397a..e92bae7fb49b 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-be/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-be/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Разгарнуць"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Згарнуць"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Закрыць"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-bg/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-bg/strings.xml index b177fa76a7d9..4a7f6a526e49 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-bg/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-bg/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Разгъване"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Свиване"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Отхвърляне"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-bn/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-bn/strings.xml index 67bb59fab828..22be594c76ae 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-bn/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-bn/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"বড় করুন"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"আড়াল করুন"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"বাতিল করুন"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-bs/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-bs/strings.xml index 31afc8b07002..3498577f3a7f 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-bs/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-bs/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Proširi"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Suzi"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Odbacivanje"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ca/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ca/strings.xml index 0f999c9a20e2..0279fdea78cb 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ca/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ca/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Desplega"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Replega"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Ignora"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-cs/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-cs/strings.xml index 144dba82e50b..82e88c476f80 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-cs/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-cs/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Rozbalit"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Sbalit"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Zavřít"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-da/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-da/strings.xml index 85497f143ef9..fc72e00434b1 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-da/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-da/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Udvid"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Skjul"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Luk"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-de/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-de/strings.xml index 9e47741a0945..cdf6da04173c 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-de/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-de/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Maximieren"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Minimieren"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Schließen"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-el/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-el/strings.xml index 0b325b5ac4cd..6f6b753714d4 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-el/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-el/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Ανάπτυξη"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Σύμπτυξη"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Παράβλεψη"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-en-rAU/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-en-rAU/strings.xml index 2539aa040a60..bb98403afa91 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-en-rAU/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expand"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Collapse"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Dismiss"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-en-rCA/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-en-rCA/strings.xml index 2539aa040a60..bb98403afa91 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-en-rCA/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expand"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Collapse"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Dismiss"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-en-rGB/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-en-rGB/strings.xml index 2539aa040a60..bb98403afa91 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-en-rGB/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expand"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Collapse"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Dismiss"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-en-rIN/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-en-rIN/strings.xml index 2539aa040a60..bb98403afa91 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-en-rIN/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expand"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Collapse"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Dismiss"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-es-rUS/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-es-rUS/strings.xml index c976a2ed7757..8e70d7c6ed60 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-es-rUS/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expandir"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Contraer"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Descartar"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-es/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-es/strings.xml index 72ba9d11ecf1..8fc34e254d47 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-es/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-es/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Mostrar"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Ocultar"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Cerrar"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-et/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-et/strings.xml index 856360669354..92ca8492fe6c 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-et/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-et/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Laienda"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Ahenda"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Loobumine"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-eu/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-eu/strings.xml index d8c2c35aed31..e352421fdc45 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-eu/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-eu/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Zabaldu"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Tolestu"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Baztertu"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-fa/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-fa/strings.xml index 24087411b5b9..5b71864cbc7e 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-fa/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-fa/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ازهم بازکردن"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"جمع کردن"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"بستن"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-fi/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-fi/strings.xml index 0d226bf8bbe6..b4f46b5b53b9 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-fi/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-fi/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Laajenna"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Tiivistä"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Ohita"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-fr-rCA/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-fr-rCA/strings.xml index fecfaa275e5e..d5495df76ced 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-fr-rCA/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Développer"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Réduire"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Fermer"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-fr/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-fr/strings.xml index fecfaa275e5e..d5495df76ced 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-fr/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-fr/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Développer"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Réduire"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Fermer"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-gl/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-gl/strings.xml index 7999aa1b4658..1f7bb4285b80 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-gl/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-gl/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Despregar"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Contraer"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Pechar"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-gu/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-gu/strings.xml index 1457d34d3691..90a6c4e0fa4f 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-gu/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-gu/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"મોટું કરો"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"નાનું કરો"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"છોડી દો"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-hi/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-hi/strings.xml index 856379aaea84..e24aa793da80 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-hi/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-hi/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"बड़ा करें"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"छोटा करें"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"खारिज करें"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-hr/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-hr/strings.xml index 2d637f4a94c0..9d95ca936b10 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-hr/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-hr/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Proširi"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Sažmi"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Odbaci"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-hu/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-hu/strings.xml index 42731635f35c..88e54d248fd5 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-hu/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-hu/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Kibontás"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Összecsukás"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Elvetés"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-hy/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-hy/strings.xml index 2fc65f0cb149..b7b09b3f6b4d 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-hy/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-hy/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Ծավալել"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Ծալել"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Փակել"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-in/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-in/strings.xml index 97c1d602b94a..bfe166c5e9d7 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-in/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-in/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Luaskan"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Ciutkan"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Tutup"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-is/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-is/strings.xml index cc4d05bc869c..d905546e7d36 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-is/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-is/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Stækka"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Minnka"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Loka"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-it/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-it/strings.xml index 8edcf2450b22..88a7a60d73a9 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-it/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-it/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Espandi"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Comprimi"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Ignora"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-iw/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-iw/strings.xml index 784bd8e34789..80e48aca8497 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-iw/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-iw/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"הרחבה"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"כיווץ"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"סגירה"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ja/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ja/strings.xml index 4e7287c4eedd..8cd92737db31 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ja/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ja/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"開く"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"閉じる"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"閉じる"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ka/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ka/strings.xml index ec8f1ddaad7d..ab8b37092c84 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ka/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ka/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"გაფართოება"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ჩაკეცვა"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"დახურვა"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-kk/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-kk/strings.xml index 329ccbbcddde..801e938ceea7 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-kk/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-kk/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Жаю"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Жию"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Жабу"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-km/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-km/strings.xml index 5ca0269e8eb8..36d81e6213b2 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-km/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-km/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ពង្រីក"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"បង្រួម"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"ច្រានចោល"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-kn/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-kn/strings.xml index 3fc1fcc728a7..c11b77cb2ef1 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-kn/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-kn/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ವಿಸ್ತೃತಗೊಳಿಸಿ"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ಕುಗ್ಗಿಸಿ"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"ವಜಾಗೊಳಿಸಿ"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ko/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ko/strings.xml index 05d4921064cc..0724d5b99d32 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ko/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ko/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"펼치기"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"접기"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"닫기"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ky/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ky/strings.xml index 4f5b8dc3643d..b2c16e940e15 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ky/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ky/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Жайып көрсөтүү"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Жыйыштыруу"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Жабуу"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-lo/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-lo/strings.xml index d6ec47939596..4e48b900563c 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-lo/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-lo/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ຂະຫຍາຍ"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ຫຍໍ້ລົງ"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"ປິດໄວ້"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-lt/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-lt/strings.xml index 54076c4fd3c2..a79877adb536 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-lt/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-lt/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Išskleisti"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Sutraukti"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Uždaryti"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-lv/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-lv/strings.xml index 2f87b0eb7abe..aa2bd8c64efb 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-lv/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-lv/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Izvērst"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Sakļaut"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Nerādīt"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-mk/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-mk/strings.xml index b4f8fb901e26..704deb6d197f 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-mk/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-mk/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Прошири"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Собери"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Отфрли"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ml/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ml/strings.xml index c68141e31d96..e83d44db6994 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ml/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ml/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"വികസിപ്പിക്കുക"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ചുരുക്കുക"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"ഡിസ്മിസ് ചെയ്യുക"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-mn/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-mn/strings.xml index 86b333d115d0..dda19c3bc510 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-mn/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-mn/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Дэлгэх"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Хураах"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Хаах"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-mr/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-mr/strings.xml index db9d42280528..26640cc895d0 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-mr/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-mr/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"विस्तार करा"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"कोलॅप्स करा"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"डिसमिस करा"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ms/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ms/strings.xml index 1ffa5a083575..31a93ad67e85 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ms/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ms/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Kembangkan"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Kuncupkan"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Ketepikan"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-my/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-my/strings.xml index 6f79acc6e8ad..22aa721edb92 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-my/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-my/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ပိုပြပါ"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"လျှော့ပြပါ"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"ပယ်ရန်"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-nb/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-nb/strings.xml index 359c9abe316e..c08ea5492888 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-nb/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-nb/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Vis"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Skjul"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Lukk"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ne/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ne/strings.xml index 374fd31129c9..b2ccbc5ef90b 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ne/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ne/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"एक्स्पान्ड गर्नुहोस्"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"कोल्याप्स गर्नुहोस्"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"बन्द गर्नुहोस्"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-nl/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-nl/strings.xml index 76a4f9996340..7469d3f34ee4 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-nl/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-nl/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Uitvouwen"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Samenvouwen"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Sluiten"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-or/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-or/strings.xml index 1e1e87025986..18701e87034f 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-or/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-or/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ବିସ୍ତାର କରନ୍ତୁ"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ସଙ୍କୁଚିତ କରନ୍ତୁ"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"ଖାରଜ କରନ୍ତୁ"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-pa/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-pa/strings.xml index 48a756b81c9c..a47dec4030d2 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-pa/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-pa/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ਵਿਸਤਾਰ ਕਰੋ"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ਸਮੇਟੋ"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"ਖਾਰਜ ਕਰੋ"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-pl/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-pl/strings.xml index da273b3bd137..ad3bf851e34b 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-pl/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-pl/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Rozwiń"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Zwiń"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Zamknij"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-pt-rBR/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-pt-rBR/strings.xml index 4e3d0e624d16..b18b025dfb2f 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-pt-rBR/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Abrir"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Fechar"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Dispensar"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-pt-rPT/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-pt-rPT/strings.xml index 58bd936a8bae..185e7bdc4c3c 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-pt-rPT/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Expandir"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Reduzir"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Ignorar"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-pt/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-pt/strings.xml index 4e3d0e624d16..b18b025dfb2f 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-pt/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-pt/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Abrir"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Fechar"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Dispensar"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ro/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ro/strings.xml index ec208843efa4..2b705cfd4708 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ro/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ro/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Extinde"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Restrânge"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Închide"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ru/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ru/strings.xml index ba6ab9687d41..ec17fb956862 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ru/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ru/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Развернуть"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Свернуть"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Закрыть"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-si/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-si/strings.xml index 9adb6466c9a4..e7351cda575b 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-si/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-si/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"දිග හරින්න"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"හකුළන්න"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"අස් කරන්න"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-sk/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sk/strings.xml index 574ee839a089..64ad93730023 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-sk/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-sk/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Rozbaliť"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Zbaliť"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Zavrieť"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-sl/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sl/strings.xml index 6fd67c59ff3d..4b2483776edf 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-sl/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-sl/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Razširi"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Strni"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Opusti"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-sq/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sq/strings.xml index e02ecbfada36..8accb18c9aa0 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-sq/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-sq/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Zgjero"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Palos"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Hiq"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-sr/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sr/strings.xml index 35f6aa3a635a..376276bb48c7 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-sr/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-sr/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Прошири"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Скупи"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Одбаците"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-sv/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sv/strings.xml index 241683984626..67d398406360 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-sv/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-sv/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Utöka"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Komprimera"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Stäng"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-sw/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-sw/strings.xml index 9a6075842a22..81cb868fc43b 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-sw/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-sw/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Panua"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Kunja"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Ondoa"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ta/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ta/strings.xml index 4a0fb4d96e03..27bae1f2846c 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ta/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ta/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"விரிவாக்கும்"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"சுருக்கும்"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"மூடும்"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-te/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-te/strings.xml index 706e225560c1..55a1c3ab924c 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-te/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-te/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"విస్తరించండి"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"కుదించండి"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"విస్మరించండి"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-th/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-th/strings.xml index d6dce9c076c9..895143e5f5bb 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-th/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-th/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"ขยาย"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"ยุบ"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"ปิด"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-tl/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-tl/strings.xml index ef5825ff1c3e..704aeb405ed0 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-tl/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-tl/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"I-expand"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"I-collapse"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"I-dismiss"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-tr/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-tr/strings.xml index 8c7dbcfd987a..6849bfeca192 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-tr/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-tr/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Genişlet"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Daralt"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Kapat"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-uk/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-uk/strings.xml index 6da0ca81450e..f4ab5e29bfd0 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-uk/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-uk/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Розгорнути"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Згорнути"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Закрити"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-ur/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-ur/strings.xml index 2e020b4e0676..07d0de5b879c 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-ur/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-ur/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"پھیلائیں"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"سکیڑیں"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"برخاست کریں"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-uz/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-uz/strings.xml index 16e389b88405..c444171fa6b4 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-uz/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-uz/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Yoyish"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Yopish"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Yopish"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml index ec67d068123a..a6fe6ec94e01 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml @@ -104,18 +104,6 @@ <item name="android:layout_width">match_parent</item> </style> - <style name="SettingslibTextAppearance.LinkableTextStyle.Expressive" - parent="@style/TextAppearance.SettingsLib.LabelLarge"> - <item name="android:textColor">?android:attr/colorAccent</item> - </style> - - <style name="SettingslibTextButtonStyle.Expressive" - parent="@style/Widget.Material3Expressive.Button.TextButton.Icon"> - <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - </style> - <style name="SettingsLibCardStyle" parent=""> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">wrap_content</item> diff --git a/packages/SettingsLib/SettingsTheme/res/values-vi/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-vi/strings.xml index 46f3351b7964..bfd2196f170b 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-vi/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-vi/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Mở rộng"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Thu gọn"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Đóng"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-zh-rCN/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-zh-rCN/strings.xml index ea5f29b2413b..1b949be434f5 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-zh-rCN/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"展开"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"收起"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"关闭"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-zh-rHK/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-zh-rHK/strings.xml index 36203139566c..d3555b4e0ea3 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-zh-rHK/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"展開"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"收合"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"關閉"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-zh-rTW/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-zh-rTW/strings.xml index 36203139566c..d3555b4e0ea3 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-zh-rTW/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"展開"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"收合"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"關閉"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-zu/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-zu/strings.xml index 725d8bc27b2f..91d184614b32 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-zu/strings.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-zu/strings.xml @@ -19,4 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_expressive_text_expand" msgid="7520894876795775876">"Nweba"</string> <string name="settingslib_expressive_text_collapse" msgid="5625043934702341576">"Goqa"</string> + <string name="settingslib_dismiss_button_content_description" msgid="6466433970910120385">"Chitha"</string> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values/styles_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values/styles_expressive.xml index f73e100906c8..686c1488fb62 100644 --- a/packages/SettingsLib/SettingsTheme/res/values/styles_expressive.xml +++ b/packages/SettingsLib/SettingsTheme/res/values/styles_expressive.xml @@ -250,4 +250,16 @@ <item name="android:lineHeight" tools:targetApi="28">16sp</item> <item name="android:textAllCaps">false</item> </style> + + <style name="SettingslibTextAppearance.LinkableTextStyle.Expressive" + parent="@style/TextAppearance.SettingsLib.LabelLarge"> + <item name="android:textColor">?android:attr/colorAccent</item> + </style> + + <style name="SettingslibTextButtonStyle.Expressive" + parent="@style/Widget.Material3Expressive.Button.TextButton.Icon"> + <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + </style> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index aa85c1aadb12..43e9cfdc7d7f 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -683,9 +683,9 @@ <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Du kan gemme eller slette din aktivitet ved afslutning"</string> <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Nulstil for at slette sessionsaktiviteten nu, eller gem eller slet aktivitet ved afslutning"</string> <string name="user_image_photo_selector" msgid="433658323306627093">"Vælg billede"</string> - <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"For mange forkerte forsøg. Dataene på denne enhed slettes."</string> - <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"For mange forkerte forsøg. Denne bruger slettes."</string> - <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"For mange forkerte forsøg. Denne arbejdsprofil og de tilhørende data slettes."</string> + <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"For mange mislykkede forsøg. Dataene på denne enhed slettes."</string> + <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"For mange mislykkede forsøg. Denne bruger slettes."</string> + <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"For mange mislykkede forsøg. Denne arbejdsprofil og de tilhørende data slettes."</string> <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Luk"</string> <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Enhedens standardindstilling"</string> <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiveret"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java index 7d5eece6c30e..84156429809b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java @@ -1087,8 +1087,9 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { private String generateRandomPassword() { String randomUUID = UUID.randomUUID().toString(); - // first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx - return randomUUID.substring(0, 8) + randomUUID.substring(9, 13); + // first 16 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx + return randomUUID.substring(0, 8) + randomUUID.substring(9, 13) + randomUUID.substring(14, + 18); } private void registerContentObserver() { diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index d936a5c699c7..27a3cf1198b2 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -291,5 +291,6 @@ public class SecureSettings { Settings.Secure.FACE_KEYGUARD_ENABLED, Settings.Secure.FINGERPRINT_APP_ENABLED, Settings.Secure.FINGERPRINT_KEYGUARD_ENABLED, + Settings.Secure.DUAL_SHADE, }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index 919c3c4721f2..8dca39fdc107 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -460,5 +460,6 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.FACE_KEYGUARD_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.FINGERPRINT_APP_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.FINGERPRINT_KEYGUARD_ENABLED, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.DUAL_SHADE, BOOLEAN_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index c1c3e04d46fd..fc402d45c3ec 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -89,6 +89,7 @@ import java.io.OutputStream; import java.time.DateTimeException; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Objects; @@ -97,7 +98,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; -import java.util.HashMap; import java.util.zip.CRC32; /** @@ -214,6 +214,17 @@ public class SettingsBackupAgent extends BackupAgentHelper { "failed_to_restore_softap_config"; private static final String ERROR_FAILED_TO_RESTORE_WIFI_CONFIG = "failed_to_restore_wifi_config"; + private static final String ERROR_FAILED_TO_RESTORE_SIM_SPECIFIC_SETTINGS = + "failed_to_restore_sim_specific_settings"; + private static final String ERROR_FAILED_TO_CONVERT_NETWORK_POLICIES = + "failed_to_convert_network_policies"; + private static final String ERROR_UNKNOWN_BACKUP_SERIALIZATION_VERSION = + "unknown_backup_serialization_version"; + private static final String INTERRUPTED_EXCEPTION = "interrupted_exception"; + private static final String ERROR_FAILED_TO_RETRIEVE_WIFI_SETTINGS_BACKUP_DATA = + "failed_to_retrieve_wifi_settings_backup_data"; + private static final String ERROR_FAILED_TO_RESTORE_WIFI_SETTINGS_BACKUP_DATA = + "failed_to_restore_wifi_settings_backup_data"; // Name of the temporary file we use during full backup/restore. This is @@ -1436,6 +1447,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { try { out.writeInt(NETWORK_POLICIES_BACKUP_VERSION); out.writeInt(policies.length); + int numberOfPoliciesBackedUp = 0; for (NetworkPolicy policy : policies) { // We purposefully only backup policies that the user has // defined; any inferred policies might include @@ -1445,13 +1457,25 @@ public class SettingsBackupAgent extends BackupAgentHelper { out.writeByte(BackupUtils.NOT_NULL); out.writeInt(marshaledPolicy.length); out.write(marshaledPolicy); + if (areAgentMetricsEnabled) { + numberOfPoliciesBackedUp++; + } } else { out.writeByte(BackupUtils.NULL); } } + if (areAgentMetricsEnabled) { + numberOfSettingsPerKey.put(KEY_NETWORK_POLICIES, numberOfPoliciesBackedUp); + } } catch (IOException ioe) { Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage()); baos.reset(); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsBackupFailed( + KEY_NETWORK_POLICIES, + policies.length, + ERROR_FAILED_TO_CONVERT_NETWORK_POLICIES); + } } } return baos.toByteArray(); @@ -1502,6 +1526,12 @@ public class SettingsBackupAgent extends BackupAgentHelper { try { int version = in.readInt(); if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) { + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + KEY_NETWORK_POLICIES, + /* count= */ 1, + ERROR_UNKNOWN_BACKUP_SERIALIZATION_VERSION); + } throw new BackupUtils.BadVersionException( "Unknown Backup Serialization Version"); } @@ -1518,10 +1548,20 @@ public class SettingsBackupAgent extends BackupAgentHelper { } // Only set the policies if there was no error in the restore operation networkPolicyManager.setNetworkPolicies(policies); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger + .logItemsRestored(KEY_NETWORK_POLICIES, policies.length); + } } catch (NullPointerException | IOException | BackupUtils.BadVersionException | DateTimeException e) { // NPE can be thrown when trying to instantiate a NetworkPolicy Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage()); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + KEY_NETWORK_POLICIES, + /* count= */ 1, + ERROR_FAILED_TO_CONVERT_NETWORK_POLICIES); + } } } } @@ -1592,7 +1632,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { return true; } - private byte[] getSimSpecificSettingsData() { + @VisibleForTesting + byte[] getSimSpecificSettingsData() { byte[] simSpecificData = new byte[0]; PackageManager packageManager = getBaseContext().getPackageManager(); if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { @@ -1600,17 +1641,36 @@ public class SettingsBackupAgent extends BackupAgentHelper { simSpecificData = subManager.getAllSimSpecificSettingsForBackup(); Log.i(TAG, "sim specific data of length + " + simSpecificData.length + " successfully retrieved"); + if (areAgentMetricsEnabled) { + // We're unable to determine how many settings this includes, so we'll just log 1. + numberOfSettingsPerKey.put(KEY_SIM_SPECIFIC_SETTINGS_2, 1); + } } return simSpecificData; } - private void restoreSimSpecificSettings(byte[] data) { + @VisibleForTesting + void restoreSimSpecificSettings(byte[] data) { PackageManager packageManager = getBaseContext().getPackageManager(); boolean hasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); if (hasTelephony) { SubscriptionManager subManager = SubscriptionManager.from(getBaseContext()); - subManager.restoreAllSimSpecificSettingsFromBackup(data); + if (areAgentMetricsEnabled) { + try { + subManager.restoreAllSimSpecificSettingsFromBackup(data); + mBackupRestoreEventLogger + .logItemsRestored(KEY_SIM_SPECIFIC_SETTINGS_2, /* count= */ 1); + } catch (Exception e) { + mBackupRestoreEventLogger + .logItemsRestoreFailed( + KEY_SIM_SPECIFIC_SETTINGS_2, + /* count= */ 1, + ERROR_FAILED_TO_RESTORE_SIM_SPECIFIC_SETTINGS); + } + } else { + subManager.restoreAllSimSpecificSettingsFromBackup(data); + } } } @@ -1637,20 +1697,49 @@ public class SettingsBackupAgent extends BackupAgentHelper { }); // cts requires B&R with 10 seconds if (latch.await(10, TimeUnit.SECONDS) && backupWifiData.value != null) { + if (areAgentMetricsEnabled) { + numberOfSettingsPerKey.put(KEY_WIFI_SETTINGS_BACKUP_DATA, 1); + } return backupWifiData.value; } } catch (InterruptedException ie) { Log.e(TAG, "fail to retrieveWifiBackupData, " + ie); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsBackupFailed( + KEY_WIFI_SETTINGS_BACKUP_DATA, + /* count= */ 1, + INTERRUPTED_EXCEPTION); + } } Log.e(TAG, "fail to retrieveWifiBackupData"); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsBackupFailed( + KEY_WIFI_SETTINGS_BACKUP_DATA, + /* count= */ 1, + ERROR_FAILED_TO_RETRIEVE_WIFI_SETTINGS_BACKUP_DATA); + } return new byte[0]; } - private void restoreWifiData(byte[] data) { + @VisibleForTesting + void restoreWifiData(byte[] data) { if (DEBUG_BACKUP) { Log.v(TAG, "Applying restored all wifi data"); } - mWifiManager.restoreWifiBackupData(data); + if (areAgentMetricsEnabled) { + try { + mWifiManager.restoreWifiBackupData(data); + mBackupRestoreEventLogger.logItemsRestored( + KEY_WIFI_SETTINGS_BACKUP_DATA, /* count= */ 1); + } catch (Exception e) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + KEY_WIFI_SETTINGS_BACKUP_DATA, + /* count= */ 1, + ERROR_FAILED_TO_RESTORE_WIFI_SETTINGS_BACKUP_DATA); + } + } else { + mWifiManager.restoreWifiBackupData(data); + } } private void updateWindowManagerIfNeeded(Integer previousDensity) { @@ -1664,8 +1753,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { if (previousDensity == null || previousDensity != newDensity) { // From nothing to something is a change. - DisplayDensityConfiguration.setForcedDisplayDensity( - Display.DEFAULT_DISPLAY, newDensity); + DisplayDensityConfiguration.setForcedDisplayDensity(getBaseContext(), + info -> info.type == Display.TYPE_INTERNAL, newDensity); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 0f6311552de9..c98a741f8254 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -18,10 +18,13 @@ package com.android.providers.settings; import static android.os.Process.FIRST_APPLICATION_UID; +import static com.android.aconfig_new_storage.Flags.enableAconfigStorageDaemon; + import android.aconfig.Aconfig.flag_permission; import android.aconfig.Aconfig.flag_state; import android.aconfig.Aconfig.parsed_flag; import android.aconfig.Aconfig.parsed_flags; +import android.aconfigd.AconfigdFlagInfo; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -65,14 +68,10 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; -import java.io.InputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.PosixFileAttributes; -import java.nio.file.attribute.PosixFilePermission; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -84,18 +83,6 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; -// FOR ACONFIGD TEST MISSION AND ROLLOUT -import java.io.DataInputStream; -import java.io.DataOutputStream; -import android.util.proto.ProtoInputStream; -import android.aconfigd.Aconfigd.StorageRequestMessage; -import android.aconfigd.Aconfigd.StorageRequestMessages; -import android.aconfigd.Aconfigd.StorageReturnMessage; -import android.aconfigd.Aconfigd.StorageReturnMessages; -import android.aconfigd.AconfigdClientSocket; -import android.aconfigd.AconfigdFlagInfo; -import android.aconfigd.AconfigdJavaUtils; -import static com.android.aconfig_new_storage.Flags.enableAconfigStorageDaemon; /** * This class contains the state for one type of settings. It is responsible * for saving the state asynchronously to an XML file after a mutation and @@ -393,22 +380,6 @@ public class SettingsState { getAllAconfigFlagsFromSettings(mAconfigDefaultFlags); } } - - if (isConfigSettingsKey(mKey)) { - requests = handleBulkSyncToNewStorage(mAconfigDefaultFlags); - } - } - - if (enableAconfigStorageDaemon()) { - if (isConfigSettingsKey(mKey)){ - AconfigdClientSocket localSocket = AconfigdJavaUtils.getAconfigdClientSocket(); - if (requests != null) { - InputStream res = localSocket.send(requests.getBytes()); - if (res == null) { - Slog.w(LOG_TAG, "Bulk sync request to acongid failed."); - } - } - } } } @@ -482,87 +453,6 @@ public class SettingsState { return flag; } - - // TODO(b/341764371): migrate aconfig flag push to GMS core - @VisibleForTesting - @GuardedBy("mLock") - public ProtoOutputStream handleBulkSyncToNewStorage( - Map<String, AconfigdFlagInfo> aconfigFlagMap) { - // get marker or add marker if it does not exist - Setting markerSetting = mSettings.get(BULK_SYNC_MARKER); - int localCounter = 0; - if (markerSetting == null) { - markerSetting = new Setting(BULK_SYNC_MARKER, "0", false, "aconfig", "aconfig"); - mSettings.put(BULK_SYNC_MARKER, markerSetting); - } - try { - localCounter = Integer.parseInt(markerSetting.value); - } catch (NumberFormatException e) { - // reset local counter - markerSetting.value = "0"; - } - - if (enableAconfigStorageDaemon()) { - Setting bulkSyncCounter = mSettings.get(BULK_SYNC_TRIGGER_COUNTER); - int serverCounter = 0; - if (bulkSyncCounter != null) { - try { - serverCounter = Integer.parseInt(bulkSyncCounter.value); - } catch (NumberFormatException e) { - // reset the local value of server counter - bulkSyncCounter.value = "0"; - } - } - - boolean shouldSync = localCounter < serverCounter; - if (!shouldSync) { - // CASE 1, flag is on, bulk sync marker true, nothing to do - return null; - } else { - // CASE 2, flag is on, bulk sync marker false. Do following two tasks - // (1) Do bulk sync here. - // (2) After bulk sync, set marker to true. - - // first add storage reset request - ProtoOutputStream requests = new ProtoOutputStream(); - AconfigdJavaUtils.writeResetStorageRequest(requests); - - // loop over all settings and add flag override requests - for (AconfigdFlagInfo flag : aconfigFlagMap.values()) { - // don't sync read_only flags - if (!flag.getIsReadWrite()) { - continue; - } - - if (flag.getHasServerOverride()) { - AconfigdJavaUtils.writeFlagOverrideRequest( - requests, - flag.getPackageName(), - flag.getFlagName(), - flag.getServerFlagValue(), - StorageRequestMessage.SERVER_ON_REBOOT); - } - - if (flag.getHasLocalOverride()) { - AconfigdJavaUtils.writeFlagOverrideRequest( - requests, - flag.getPackageName(), - flag.getFlagName(), - flag.getLocalFlagValue(), - StorageRequestMessage.LOCAL_ON_REBOOT); - } - } - - // mark sync has been done - markerSetting.value = String.valueOf(serverCounter); - scheduleWriteIfNeededLocked(); - return requests; - } - } else { - return null; - } - } - @GuardedBy("mLock") private void loadAconfigDefaultValuesLocked(List<String> filePaths) { for (String fileName : filePaths) { diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 9aad5d5f8367..246aa7158cab 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -178,6 +178,7 @@ public class SettingsBackupTest { Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, + Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_EXPERIENCE_FEATURES, Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, Settings.Global.DEVELOPMENT_FORCE_RTL, Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java index 6e5b602c02c5..48c360b635ea 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java @@ -18,6 +18,8 @@ package com.android.providers.settings; import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_WIFI_NEW_CONFIG; import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SOFTAP_CONFIG; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SIM_SPECIFIC_SETTINGS_2; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_WIFI_SETTINGS_BACKUP_DATA; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; @@ -59,6 +61,7 @@ import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.provider.settings.validators.SettingsValidators; import android.provider.settings.validators.Validator; +import android.telephony.SubscriptionManager; import android.test.mock.MockContentProvider; import android.test.mock.MockContentResolver; @@ -136,6 +139,7 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { @Mock private BackupDataInput mBackupDataInput; @Mock private BackupDataOutput mBackupDataOutput; @Mock private static WifiManager mWifiManager; + @Mock private static SubscriptionManager mSubscriptionManager; private TestFriendlySettingsBackupAgent mAgentUnderTest; private Context mContext; @@ -906,6 +910,110 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { assertNull(getLoggingResultForDatatype(KEY_WIFI_NEW_CONFIG, mAgentUnderTest)); } + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + getSimSpecificSettingsData_agentMetricsAreEnabled_numberOfSettingsInKeyAreRecorded() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.BACKUP); + when(mSubscriptionManager.getAllSimSpecificSettingsForBackup()).thenReturn(new byte[0]); + + mAgentUnderTest.getSimSpecificSettingsData(); + + assertEquals(mAgentUnderTest.getNumberOfSettingsPerKey(KEY_SIM_SPECIFIC_SETTINGS_2), 1); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreSimSpecificSettings_agentMetricsAreEnabled_restoreIsSuccessful_successMetricsAreLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doNothing().when(mSubscriptionManager).restoreAllSimSpecificSettingsFromBackup(any()); + + mAgentUnderTest.restoreSimSpecificSettings(new byte[0]); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(KEY_SIM_SPECIFIC_SETTINGS_2, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getSuccessCount(), 1); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreSimSpecificSettings_agentMetricsAreEnabled_restoreIsNotSuccessful_failureMetricsAreLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doThrow(new RuntimeException()) + .when(mSubscriptionManager) + .restoreAllSimSpecificSettingsFromBackup(any()); + + mAgentUnderTest.restoreSimSpecificSettings(new byte[0]); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(KEY_SIM_SPECIFIC_SETTINGS_2, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getFailCount(), 1); + } + + @Test + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreSimSpecificSettings_agentMetricsAreNotEnabled_metricsAreNotLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doNothing().when(mSubscriptionManager).restoreAllSimSpecificSettingsFromBackup(any()); + + mAgentUnderTest.restoreSimSpecificSettings(new byte[0]); + + assertNull(getLoggingResultForDatatype(KEY_SIM_SPECIFIC_SETTINGS_2, mAgentUnderTest)); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreWifiData_agentMetricsAreEnabled_restoreIsSuccessful_successMetricsAreLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doNothing().when(mWifiManager).restoreWifiBackupData(any()); + + mAgentUnderTest.restoreWifiData(new byte[0]); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(KEY_WIFI_SETTINGS_BACKUP_DATA, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getSuccessCount(), 1); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreWifiData_agentMetricsAreEnabled_restoreIsNotSuccessful_failureMetricsAreLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doThrow(new RuntimeException()).when(mWifiManager).restoreWifiBackupData(any()); + + mAgentUnderTest.restoreWifiData(new byte[0]); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(KEY_WIFI_SETTINGS_BACKUP_DATA, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getFailCount(), 1); + } + + @Test + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreWifiData_agentMetricsAreDisabled_metricsAreNotLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doNothing().when(mWifiManager).restoreWifiBackupData(any()); + + mAgentUnderTest.restoreWifiData(new byte[0]); + + assertNull(getLoggingResultForDatatype(KEY_WIFI_SETTINGS_BACKUP_DATA, mAgentUnderTest)); + } + private byte[] generateBackupData(Map<String, String> keyValueData) { int totalBytes = 0; for (String key : keyValueData.keySet()) { @@ -1106,10 +1214,14 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { @Override public Object getSystemService(String name) { - if (name.equals(Context.WIFI_SERVICE)) { - return mWifiManager; + switch (name) { + case Context.WIFI_SERVICE: + return mWifiManager; + case Context.TELEPHONY_SUBSCRIPTION_SERVICE: + return mSubscriptionManager; + default: + return super.getSystemService(name); } - return super.getSystemService(name); } } diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java index 6e7576631147..13eb1d4b2603 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java @@ -31,19 +31,20 @@ import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.Xml; -import android.util.proto.ProtoOutputStream; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.modules.utils.TypedXmlSerializer; -import android.platform.test.annotations.EnableFlags; -import android.platform.test.annotations.DisableFlags; -import android.platform.test.flag.junit.SetFlagsRule; - import com.google.common.base.Strings; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -52,11 +53,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class SettingsStateTest { @@ -1085,124 +1081,6 @@ public class SettingsStateTest { assertTrue(flag1.getHasLocalOverride()); } - @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - - @Test - @EnableFlags(com.android.aconfig_new_storage.Flags.FLAG_ENABLE_ACONFIG_STORAGE_DAEMON) - public void testHandleBulkSyncWithAconfigdEnabled() { - int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); - Object lock = new Object(); - SettingsState settingsState = - new SettingsState( - InstrumentationRegistry.getContext(), - lock, - mSettingsFile, - configKey, - SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, - Looper.getMainLooper()); - - Map<String, AconfigdFlagInfo> flags = new HashMap<>(); - flags.put( - "com.android.flags/flag1", - AconfigdFlagInfo.newBuilder() - .setPackageName("com.android.flags") - .setFlagName("flag1") - .setBootFlagValue("true") - .setIsReadWrite(true) - .build()); - - flags.put( - "com.android.flags/flag2", - AconfigdFlagInfo.newBuilder() - .setPackageName("com.android.flags") - .setFlagName("flag2") - .setBootFlagValue("true") - .setIsReadWrite(false) - .build()); - - String bulkSyncMarker = "aconfigd_marker/bulk_synced"; - String bulkSyncCounter = - "core_experiments_team_internal/" + - "BulkSyncTriggerCounterFlag__bulk_sync_trigger_counter"; - - synchronized (lock) { - settingsState.insertSettingLocked(bulkSyncMarker, "0", null, false, "aconfig"); - settingsState.insertSettingLocked(bulkSyncCounter, "1", null, false, - "com.google.android.platform.core_experiments_team_internal"); - - // first bulk sync - ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags); - assertTrue(requests != null); - String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); - assertEquals("1", value); - - // send time should no longer bulk sync - requests = settingsState.handleBulkSyncToNewStorage(flags); - assertNull(requests); - value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); - assertEquals("1", value); - - // won't sync if the marker is string - settingsState.insertSettingLocked(bulkSyncMarker, "true", null, false, "aconfig"); - settingsState.insertSettingLocked(bulkSyncCounter, "0", null, false, - "com.google.android.platform.core_experiments_team_internal"); - requests = settingsState.handleBulkSyncToNewStorage(flags); - assertNull(requests); - value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); - assertEquals("0", value); - - // won't sync if the marker and counter value are the same - settingsState.insertSettingLocked(bulkSyncMarker, "1", null, false, "aconfig"); - settingsState.insertSettingLocked(bulkSyncCounter, "1", null, false, - "com.google.android.platform.core_experiments_team_internal"); - requests = settingsState.handleBulkSyncToNewStorage(flags); - assertNull(requests); - value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); - assertEquals("1", value); - } - } - - @Test - @DisableFlags(com.android.aconfig_new_storage.Flags.FLAG_ENABLE_ACONFIG_STORAGE_DAEMON) - public void testHandleBulkSyncWithAconfigdDisabled() { - int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); - Object lock = new Object(); - SettingsState settingsState = new SettingsState( - InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, - SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); - - Map<String, AconfigdFlagInfo> flags = new HashMap<>(); - String bulkSyncMarker = "aconfigd_marker/bulk_synced"; - String bulkSyncCounter = - "core_experiments_team_internal/" + - "BulkSyncTriggerCounterFlag__bulk_sync_trigger_counter"; - synchronized (lock) { - settingsState.insertSettingLocked("aconfigd_marker/bulk_synced", - "true", null, false, "aconfig"); - - // when aconfigd is off, should change the marker to false - ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags); - assertNull(requests); - String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); - assertEquals("0", value); - - // marker started with false value, after call, it should remain false - requests = settingsState.handleBulkSyncToNewStorage(flags); - assertNull(requests); - value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); - assertEquals("0", value); - - // won't sync - settingsState.insertSettingLocked(bulkSyncMarker, "0", null, false, "aconfig"); - settingsState.insertSettingLocked(bulkSyncCounter, "1", null, false, - "com.google.android.platform.core_experiments_team_internal"); - requests = settingsState.handleBulkSyncToNewStorage(flags); - assertNull(requests); - value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); - assertEquals("0", value); - } - } - @Test public void testGetAllAconfigFlagsFromSettings() throws Exception { final Object lock = new Object(); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index b53198d8ae98..e5e8418d5f18 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -392,6 +392,9 @@ <!-- To be able to decipher default applications for certain roles in shortcut helper --> <uses-permission android:name="android.permission.MANAGE_DEFAULT_APPLICATIONS" /> + <!-- To be able to set unrestricted system gesture exclusion rects --> + <uses-permission android:name="android.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION"/> + <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" /> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp index 0ff856e0b91e..1d74774c7c11 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp +++ b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/Android.bp @@ -5,7 +5,7 @@ package { aconfig_declarations { name: "com_android_a11y_menu_flags", package: "com.android.systemui.accessibility.accessibilitymenu", - container: "system", + container: "system_ext", srcs: [ "accessibility.aconfig", ], diff --git a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig index 6d790114803a..bdf6d4242e68 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig +++ b/packages/SystemUI/accessibility/accessibilitymenu/aconfig/accessibility.aconfig @@ -1,5 +1,5 @@ package: "com.android.systemui.accessibility.accessibilitymenu" -container: "system" +container: "system_ext" # NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors. diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index f753316cb67a..01ee2cd5d22b 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -186,6 +186,16 @@ flag { } flag { + name: "notifications_pinned_hun_in_shade" + namespace: "systemui" + description: "Fixes displaying pinned HUNs in the Shade, making sure that their y and z positions are correct." + bug: "385041854" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "pss_app_selector_recents_split_screen" namespace: "systemui" description: "Allows recent apps selected for partial screenshare to be launched in split screen mode" @@ -524,6 +534,16 @@ flag { } flag { + name: "indication_text_a11y_fix" + namespace: "systemui" + description: "add double shadow to the indication text at the bottom of the lock screen" + bug: "349297241" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "rest_to_unlock" namespace: "systemui" description: "Require prolonged touch for fingerprint authentication" @@ -1769,7 +1789,14 @@ flag { flag { name: "bouncer_ui_revamp" namespace: "systemui" - description: "Updates to background (blur), button animations and font changes." + description: "Updates to background (blur) for bouncer" + bug: "370555003" +} + +flag { + name: "bouncer_ui_revamp_2" + namespace: "systemui" + description: "Updates to button animations and font changes for bouncer, bouncer_ui_revamp will cover only the blur changes." bug: "376491880" } @@ -1839,13 +1866,6 @@ flag { } flag { - name: "glanceable_hub_shortcut_button" - namespace: "systemui" - description: "Adds a shortcut button to lockscreen to show glanceable hub." - bug: "378173531" -} - -flag { name: "spatial_model_launcher_pushback" namespace: "systemui" description: "Implement the depth push scaling effect on Launcher when users pull down shade." @@ -1946,4 +1966,14 @@ flag { namespace: "systemui" description: "Show a rich ongoing notification on the always-on display (depends on ui_rich_ongoing)" bug: "369151941" +} + +flag { + name: "stabilize_heads_up_group_v2" + namespace: "systemui" + description: "Stabilize heads up groups in VisualStabilityCoordinator" + bug: "357753857" + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetector.kt new file mode 100644 index 000000000000..4927fb9dc67d --- /dev/null +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetector.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.internal.systemui.lint + +import com.android.tools.lint.detector.api.Category +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Issue +import com.android.tools.lint.detector.api.JavaContext +import com.android.tools.lint.detector.api.Scope +import com.android.tools.lint.detector.api.Severity +import com.android.tools.lint.detector.api.SourceCodeScanner +import com.android.tools.lint.detector.api.getReceiver +import com.intellij.psi.PsiMethod +import org.jetbrains.uast.UCallExpression +import org.jetbrains.uast.getContainingUFile + +/** + * Detects test function naming violations regarding use of the backtick-wrapped space-allowed + * feature of Kotlin functions. + */ +class RunTestShouldUseKosmosDetector : Detector(), SourceCodeScanner { + override fun getApplicableMethodNames() = listOf("runTest") + + override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) { + if (method.getReceiver()?.qualifiedName == "kotlinx.coroutines.test.TestScope") { + + val imports = + node.getContainingUFile()?.imports.orEmpty().mapNotNull { + it.importReference?.asSourceString() + } + if (imports.any { it == "com.android.systemui.kosmos.Kosmos" }) { + context.report( + issue = ISSUE, + scope = node, + location = context.getLocation(node.methodIdentifier), + message = + "Prefer Kosmos.runTest to TestScope.runTest in sysui tests that use Kosmos. go/kosmos-runtest", + ) + super.visitMethodCall(context, node, method) + } + } + } + + companion object { + @JvmStatic + val ISSUE = + Issue.create( + id = "RunTestShouldUseKosmos", + briefDescription = "When you can, use Kosmos.runTest instead of TestScope.runTest.", + explanation = + """ + Kosmos.runTest helps to ensure that the test uses the same coroutine + dispatchers that are used in Kosmos fixtures, preventing subtle bugs. + See go/kosmos-runtest + """, + category = Category.TESTING, + priority = 8, + severity = Severity.WARNING, + implementation = + Implementation( + RunTestShouldUseKosmosDetector::class.java, + Scope.JAVA_FILE_SCOPE, + ), + ) + } +} diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetectorTest.kt new file mode 100644 index 000000000000..41e90b863fab --- /dev/null +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetectorTest.kt @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.internal.systemui.lint + +import com.android.tools.lint.checks.infrastructure.TestFile +import com.android.tools.lint.checks.infrastructure.TestFiles +import com.android.tools.lint.checks.infrastructure.TestLintResult +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Issue +import org.junit.Test + +class RunTestShouldUseKosmosDetectorTest : SystemUILintDetectorTest() { + override fun getDetector(): Detector = RunTestShouldUseKosmosDetector() + + override fun getIssues(): List<Issue> = listOf(RunTestShouldUseKosmosDetector.ISSUE) + + @Test + fun wronglyTriesToUseScopeRunTest() { + val runOnSource = + runOnSource( + """ + package test.pkg.name + + import com.android.systemui.kosmos.Kosmos + import kotlinx.coroutines.test.runTest + import kotlinx.coroutines.test.TestScope + import org.junit.Test + + class MyTest { + val scope: TestScope + val kosmos: Kosmos + + @Test + fun badTest() = scope.runTest { + // test code + } + } + """ + ) + + runOnSource + .expectWarningCount(1) + .expect( + """ + src/test/pkg/name/MyTest.kt:13: Warning: Prefer Kosmos.runTest to TestScope.runTest in sysui tests that use Kosmos. go/kosmos-runtest [RunTestShouldUseKosmos] + fun badTest() = scope.runTest { + ~~~~~~~ + 0 errors, 1 warnings + """ + ) + } + + @Test + fun testScopeRunTestIsOKifKosmosNotUsed() { + runOnSource( + """ + package test.pkg.name + + import kotlinx.coroutines.test.runTest + import kotlinx.coroutines.test.TestScope + import org.junit.Test + + class MyTest { + val scope: TestScope + + @Test + fun okTest() = scope.runTest { + // test code + } + } + """ + ) + .expectWarningCount(0) + } + + @Test + fun otherTestScopeMethodsAreOK() { + runOnSource( + """ + package test.pkg.name + + import com.android.systemui.kosmos.Kosmos + import com.android.systemui.kosmos.runTest + import kotlinx.coroutines.test.TestScope + import org.junit.Test + + class MyTest { + val scope: TestScope + val kosmos: Kosmos + + @Test + fun okTest() = kosmos.runTest { + scope.cancel() + // test code + } + } + """ + ) + .expectWarningCount(0) + } + + @Test + fun correctlyUsesKosmosRunTest() { + runOnSource( + """ + package test.pkg.name + + import com.android.systemui.kosmos.Kosmos + import com.android.systemui.kosmos.runTest + import kotlinx.coroutines.test.TestScope + import org.junit.Test + + class MyTest { + val scope: TestScope + val kosmos: Kosmos + + @Test + fun okTest() = kosmos.runTest { + // test code + } + } + """ + ) + .expectWarningCount(0) + } + + private fun runOnSource(source: String): TestLintResult { + return lint() + .files( + TestFiles.kotlin(source).indented(), + testAnnotationStub, + runTestStub, + testScopeStub, + kosmosStub, + kosmosRunTestStub, + ) + .issues(RunTestShouldUseKosmosDetector.ISSUE) + .run() + } + + companion object { + private val testAnnotationStub: TestFile = + kotlin( + """ + package org.junit + + import java.lang.annotation.ElementType + import java.lang.annotation.Retention + import java.lang.annotation.RetentionPolicy + import java.lang.annotation.Target + + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD}) + annotation class Test + """ + ) + + private val runTestStub: TestFile = + kotlin( + """ + package kotlinx.coroutines.test + + fun TestScope.runTest( + timeout: Duration = DEFAULT_TIMEOUT.getOrThrow(), + testBody: suspend TestScope.() -> Unit + ): Unit = {} + """ + ) + + private val testScopeStub: TestFile = + kotlin( + """ + package kotlinx.coroutines.test + + class TestScope + + public fun TestScope.cancel() {} + """ + ) + + private val kosmosStub: TestFile = + kotlin( + """ + package com.android.systemui.kosmos + + class Kosmos + """ + ) + + private val kosmosRunTestStub: TestFile = + kotlin( + """ + package com.android.systemui.kosmos + + fun Kosmos.runTest(testBody: suspend Kosmos.() -> Unit) + """ + ) + } +} diff --git a/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt b/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt index a27bf8af1806..195b060932eb 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt @@ -464,13 +464,15 @@ private class NestedDraggableNode( velocity: Velocity, performFling: suspend (Velocity) -> Velocity, ): Velocity { + // Make sure we only use the velocity in this draggable orientation. + val orientationVelocity = velocity.toFloat().toVelocity() return if (overscrollEffect != null) { - overscrollEffect.applyToFling(velocity) { performFling(it) } + overscrollEffect.applyToFling(orientationVelocity) { performFling(it) } // Effects always consume the whole velocity. velocity } else { - performFling(velocity) + performFling(orientationVelocity) } } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/ContentOverscrollEffect.kt b/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/ContentOverscrollEffect.kt index 4ee6db3d516c..49e510791929 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/ContentOverscrollEffect.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/ContentOverscrollEffect.kt @@ -23,7 +23,9 @@ import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.unit.Velocity +import com.android.compose.ui.util.HorizontalSpaceVectorConverter import com.android.compose.ui.util.SpaceVectorConverter +import com.android.compose.ui.util.VerticalSpaceVectorConverter import kotlin.math.abs import kotlin.math.sign import kotlinx.coroutines.CoroutineScope @@ -40,13 +42,12 @@ interface ContentOverscrollEffect : OverscrollEffect { } open class BaseContentOverscrollEffect( - orientation: Orientation, private val animationScope: CoroutineScope, private val animationSpec: AnimationSpec<Float>, -) : ContentOverscrollEffect, SpaceVectorConverter by SpaceVectorConverter(orientation) { - +) : ContentOverscrollEffect { /** The [Animatable] that holds the current overscroll value. */ private val animatable = Animatable(initialValue = 0f, visibilityThreshold = 0.5f) + private var lastConverter: SpaceVectorConverter? = null override val overscrollDistance: Float get() = animatable.value @@ -59,6 +60,15 @@ open class BaseContentOverscrollEffect( source: NestedScrollSource, performScroll: (Offset) -> Offset, ): Offset { + val converter = converterOrNull(delta.x, delta.y) ?: return performScroll(delta) + return converter.applyToScroll(delta, source, performScroll) + } + + private fun SpaceVectorConverter.applyToScroll( + delta: Offset, + source: NestedScrollSource, + performScroll: (Offset) -> Offset, + ): Offset { val deltaForAxis = delta.toFloat() // If we're currently overscrolled, and the user scrolls in the opposite direction, we need @@ -106,6 +116,14 @@ open class BaseContentOverscrollEffect( velocity: Velocity, performFling: suspend (Velocity) -> Velocity, ) { + val converter = converterOrNull(velocity.x, velocity.y) ?: return + converter.applyToFling(velocity, performFling) + } + + private suspend fun SpaceVectorConverter.applyToFling( + velocity: Velocity, + performFling: suspend (Velocity) -> Velocity, + ) { // We launch a coroutine to ensure the fling animation starts after any pending [snapTo] // animations have finished. // This guarantees a smooth, sequential execution of animations on the overscroll value. @@ -117,4 +135,35 @@ open class BaseContentOverscrollEffect( } } } + + protected fun requireConverter(): SpaceVectorConverter { + return checkNotNull(lastConverter) { + "lastConverter is null, make sure to call requireConverter() only when " + + "overscrollDistance != 0f" + } + } + + private fun converterOrNull(x: Float, y: Float): SpaceVectorConverter? { + val converter: SpaceVectorConverter = + when { + x != 0f && y != 0f -> + error( + "BaseContentOverscrollEffect only supports single orientation scrolls " + + "and velocities" + ) + x == 0f && y == 0f -> lastConverter ?: return null + x != 0f -> HorizontalSpaceVectorConverter + else -> VerticalSpaceVectorConverter + } + + if (lastConverter != null) { + check(lastConverter == converter) { + "BaseContentOverscrollEffect should always be used in the same orientation" + } + } else { + lastConverter = converter + } + + return converter + } } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/OffsetOverscrollEffect.kt b/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/OffsetOverscrollEffect.kt index fc01c78f8c54..e74b185851c4 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/OffsetOverscrollEffect.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/OffsetOverscrollEffect.kt @@ -19,7 +19,7 @@ package com.android.compose.gesture.effect import androidx.annotation.VisibleForTesting import androidx.compose.animation.core.AnimationSpec import androidx.compose.foundation.OverscrollEffect -import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.OverscrollFactory import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable @@ -37,24 +37,42 @@ import androidx.compose.ui.unit.dp import kotlin.math.roundToInt import kotlinx.coroutines.CoroutineScope -/** An [OverscrollEffect] that offsets the content by the overscroll value. */ -class OffsetOverscrollEffect( - orientation: Orientation, - animationScope: CoroutineScope, - animationSpec: AnimationSpec<Float>, -) : BaseContentOverscrollEffect(orientation, animationScope, animationSpec) { - private var _node: DelegatableNode = newNode() - override val node: DelegatableNode - get() = _node +@Composable +@OptIn(ExperimentalMaterial3ExpressiveApi::class) +fun rememberOffsetOverscrollEffect( + animationSpec: AnimationSpec<Float> = MaterialTheme.motionScheme.defaultSpatialSpec() +): OffsetOverscrollEffect { + val animationScope = rememberCoroutineScope() + return remember(animationScope, animationSpec) { + OffsetOverscrollEffect(animationScope, animationSpec) + } +} - fun newNode(): DelegatableNode { - return object : Modifier.Node(), LayoutModifierNode { - override fun onDetach() { - super.onDetach() - // TODO(b/379086317) Remove this workaround: avoid to reuse the same node. - _node = newNode() - } +@Composable +@OptIn(ExperimentalMaterial3ExpressiveApi::class) +fun rememberOffsetOverscrollEffectFactory( + animationSpec: AnimationSpec<Float> = MaterialTheme.motionScheme.defaultSpatialSpec() +): OverscrollFactory { + val animationScope = rememberCoroutineScope() + return remember(animationScope, animationSpec) { + OffsetOverscrollEffectFactory(animationScope, animationSpec) + } +} +data class OffsetOverscrollEffectFactory( + private val animationScope: CoroutineScope, + private val animationSpec: AnimationSpec<Float>, +) : OverscrollFactory { + override fun createOverscrollEffect(): OverscrollEffect { + return OffsetOverscrollEffect(animationScope, animationSpec) + } +} + +/** An [OverscrollEffect] that offsets the content by the overscroll value. */ +class OffsetOverscrollEffect(animationScope: CoroutineScope, animationSpec: AnimationSpec<Float>) : + BaseContentOverscrollEffect(animationScope, animationSpec) { + override val node: DelegatableNode = + object : Modifier.Node(), LayoutModifierNode { override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints, @@ -62,11 +80,16 @@ class OffsetOverscrollEffect( val placeable = measurable.measure(constraints) return layout(placeable.width, placeable.height) { val offsetPx = computeOffset(density = this@measure, overscrollDistance) - placeable.placeRelativeWithLayer(position = offsetPx.toIntOffset()) + if (offsetPx != 0) { + placeable.placeRelativeWithLayer( + with(requireConverter()) { offsetPx.toIntOffset() } + ) + } else { + placeable.placeRelative(0, 0) + } } } } - } companion object { private val MaxDistance = 400.dp @@ -80,18 +103,6 @@ class OffsetOverscrollEffect( } } -@OptIn(ExperimentalMaterial3ExpressiveApi::class) -@Composable -fun rememberOffsetOverscrollEffect( - orientation: Orientation, - animationSpec: AnimationSpec<Float> = MaterialTheme.motionScheme.defaultSpatialSpec(), -): OffsetOverscrollEffect { - val animationScope = rememberCoroutineScope() - return remember(orientation, animationScope, animationSpec) { - OffsetOverscrollEffect(orientation, animationScope, animationSpec) - } -} - /** This converter lets you change a linear progress into a function of your choice. */ fun interface ProgressConverter { fun convert(progress: Float): Float diff --git a/packages/SystemUI/compose/core/src/com/android/compose/ui/util/SpaceVectorConverter.kt b/packages/SystemUI/compose/core/src/com/android/compose/ui/util/SpaceVectorConverter.kt index ca50e778d131..ac0e17a591dc 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/ui/util/SpaceVectorConverter.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/ui/util/SpaceVectorConverter.kt @@ -37,11 +37,11 @@ interface SpaceVectorConverter { fun SpaceVectorConverter(orientation: Orientation) = when (orientation) { - Orientation.Horizontal -> HorizontalConverter - Orientation.Vertical -> VerticalConverter + Orientation.Horizontal -> HorizontalSpaceVectorConverter + Orientation.Vertical -> VerticalSpaceVectorConverter } -private data object HorizontalConverter : SpaceVectorConverter { +data object HorizontalSpaceVectorConverter : SpaceVectorConverter { override fun Offset.toFloat() = x override fun Velocity.toFloat() = x @@ -55,7 +55,7 @@ private data object HorizontalConverter : SpaceVectorConverter { override fun Int.toIntOffset() = IntOffset(this, 0) } -private data object VerticalConverter : SpaceVectorConverter { +data object VerticalSpaceVectorConverter : SpaceVectorConverter { override fun Offset.toFloat() = y override fun Velocity.toFloat() = y diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/effect/OffsetOverscrollEffectTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/effect/OffsetOverscrollEffectTest.kt index 5a3f240deb44..e7c47fb56130 100644 --- a/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/effect/OffsetOverscrollEffectTest.kt +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/effect/OffsetOverscrollEffectTest.kt @@ -55,10 +55,7 @@ class OffsetOverscrollEffectTest { } } - private fun setupOverscrollableBox( - scrollableOrientation: Orientation, - overscrollEffectOrientation: Orientation = scrollableOrientation, - ): LayoutInfo { + private fun setupOverscrollableBox(scrollableOrientation: Orientation): LayoutInfo { val layoutSize: Dp = 200.dp var touchSlop: Float by Delegates.notNull() // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is @@ -67,7 +64,7 @@ class OffsetOverscrollEffectTest { rule.setContent { density = LocalDensity.current touchSlop = LocalViewConfiguration.current.touchSlop - val overscrollEffect = rememberOffsetOverscrollEffect(overscrollEffectOrientation) + val overscrollEffect = rememberOffsetOverscrollEffect() Box( Modifier.overscroll(overscrollEffect) @@ -102,11 +99,7 @@ class OffsetOverscrollEffectTest { @Test fun applyNoOffset_duringHorizontalOverscroll() { - val info = - setupOverscrollableBox( - scrollableOrientation = Orientation.Vertical, - overscrollEffectOrientation = Orientation.Horizontal, - ) + val info = setupOverscrollableBox(scrollableOrientation = Orientation.Vertical) rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt index fea34921b853..30dfa5bb826a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt @@ -37,6 +37,7 @@ import com.android.systemui.communal.smartspace.SmartspaceInteractionHandler import com.android.systemui.communal.ui.compose.section.AmbientStatusBarSection import com.android.systemui.communal.ui.compose.section.CommunalPopupSection import com.android.systemui.communal.ui.compose.section.CommunalToDreamButtonSection +import com.android.systemui.communal.ui.compose.section.HubOnboardingSection import com.android.systemui.communal.ui.view.layout.sections.CommunalAppWidgetSection import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines @@ -62,6 +63,7 @@ constructor( private val communalPopupSection: CommunalPopupSection, private val widgetSection: CommunalAppWidgetSection, private val communalToDreamButtonSection: CommunalToDreamButtonSection, + private val hubOnboardingSection: HubOnboardingSection, ) { @Composable @@ -83,6 +85,7 @@ constructor( modifier = Modifier.element(Communal.Elements.Grid), contentScope = this@Content, ) + with(hubOnboardingSection) { BottomSheet() } } if (communalSettingsInteractor.isV2FlagEnabled()) { Icon( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt index 7a500805809d..c972d3e3cf15 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt @@ -44,6 +44,8 @@ import androidx.compose.ui.unit.round import androidx.compose.ui.unit.toOffset import androidx.compose.ui.unit.toSize import com.android.systemui.Flags.communalWidgetResizing +import com.android.systemui.communal.domain.model.CommunalContentModel +import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.ui.compose.extensions.firstItemAtOffset import com.android.systemui.communal.ui.compose.extensions.plus import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel @@ -105,6 +107,9 @@ internal constructor( private var draggingItemDraggedDelta by mutableStateOf(Offset.Zero) private var draggingItemInitialOffset by mutableStateOf(Offset.Zero) + private val spacer = CommunalContentModel.Spacer(CommunalContentSize.Responsive(1)) + private var spacerIndex: Int? = null + private var previousTargetItemKey: Any? = null internal val draggingItemOffset: Offset @@ -140,6 +145,17 @@ internal constructor( ?.apply { draggingItemKey = key as String draggingItemInitialOffset = this.offset.toOffset() + // Add a spacer after the last widget if it is larger than the dragging widget. + // This allows overscrolling, enabling the dragging widget to be placed beyond it. + val lastWidget = contentListState.list.lastOrNull { it.isWidgetContent() } + if ( + lastWidget != null && + draggingItemLayoutInfo != null && + lastWidget.size.span > draggingItemLayoutInfo!!.span + ) { + contentListState.list.add(spacer) + spacerIndex = contentListState.list.size - 1 + } return true } @@ -162,6 +178,11 @@ internal constructor( previousTargetItemKey = null draggingItemDraggedDelta = Offset.Zero draggingItemInitialOffset = Offset.Zero + // Remove spacer, if any, when a drag gesture finishes. + spacerIndex?.let { + contentListState.list.removeAt(it) + spacerIndex = null + } } internal fun onDrag(offset: Offset, layoutDirection: LayoutDirection) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt index c7930549abe8..44c375d6ac5e 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt @@ -272,9 +272,8 @@ private fun calculateNumCellsWidth(width: Dp) = } private fun calculateNumCellsHeight(height: Dp) = - // See https://developer.android.com/develop/ui/views/layout/use-window-size-classes when { - height >= 900.dp -> 3 + height >= 1000.dp -> 3 height >= 480.dp -> 2 else -> 1 } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/HubOnboardingSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/HubOnboardingSection.kt new file mode 100644 index 000000000000..6943e9b00ed8 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/HubOnboardingSection.kt @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.ui.compose.section + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ChargingStation +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.android.systemui.communal.ui.viewmodel.HubOnboardingViewModel +import com.android.systemui.lifecycle.rememberViewModel +import com.android.systemui.res.R +import com.android.systemui.statusbar.phone.ComponentSystemUIDialog +import com.android.systemui.statusbar.phone.SystemUIDialogFactory +import com.android.systemui.statusbar.phone.createBottomSheet +import javax.inject.Inject + +class HubOnboardingSection +@Inject +constructor( + private val viewModelFactory: HubOnboardingViewModel.Factory, + private val dialogFactory: SystemUIDialogFactory, +) { + @Composable + fun BottomSheet() { + val viewModel = rememberViewModel("HubOnboardingSection") { viewModelFactory.create() } + val shouldShowHubOnboarding by + viewModel.shouldShowHubOnboarding.collectAsStateWithLifecycle(false) + + if (!shouldShowHubOnboarding) { + return + } + + HubOnboardingBottomSheet(shouldShowBottomSheet = true, dialogFactory = dialogFactory) { + viewModel.onDismissed() + } + } +} + +@Composable +private fun HubOnboardingBottomSheet( + shouldShowBottomSheet: Boolean, + dialogFactory: SystemUIDialogFactory, + onDismiss: () -> Unit, +) { + var dialog: ComponentSystemUIDialog? by remember { mutableStateOf(null) } + var dismissingDueToCancel by remember { mutableStateOf(false) } + + DisposableEffect(shouldShowBottomSheet) { + if (shouldShowBottomSheet) { + dialog = + dialogFactory + .createBottomSheet( + content = { HubOnboardingBottomSheetContent { dialog?.dismiss() } }, + isDraggable = true, + maxWidth = 627.dp, + ) + .apply { + setOnDismissListener { + // Don't set the onboarding dismissed flag if the dismiss was due to a + // cancel. Note that a "dismiss" is something initiated by the user + // (e.g. swipe down or tapping outside), while a "cancel" is a dismiss + // not initiated by the user (e.g. timing out to dream). We only want + // to mark the bottom sheet as dismissed if the user explicitly + // dismissed it. + if (!dismissingDueToCancel) { + onDismiss() + } + } + setOnCancelListener { dismissingDueToCancel = true } + show() + } + } + + onDispose { + dialog?.cancel() + dialog = null + } + } +} + +@Composable +private fun HubOnboardingBottomSheetContent(onButtonClicked: () -> Unit) { + val colors = MaterialTheme.colorScheme + Column( + modifier = Modifier.fillMaxWidth().padding(48.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Icon( + imageVector = Icons.Outlined.ChargingStation, + contentDescription = null, + modifier = Modifier.size(32.dp), + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = stringResource(R.string.hub_onboarding_bottom_sheet_title), + style = MaterialTheme.typography.headlineMedium, + ) + Spacer(modifier = Modifier.height(32.dp)) + // TODO(b/388283881): Replace with correct animations and possibly add a content description + // if necessary. + Image(painter = painterResource(R.drawable.hub_onboarding_bg), contentDescription = null) + Spacer(modifier = Modifier.height(32.dp)) + Text( + modifier = Modifier.width(300.dp), + text = stringResource(R.string.hub_onboarding_bottom_sheet_text), + textAlign = TextAlign.Center, + ) + Spacer(modifier = Modifier.height(32.dp)) + Button( + modifier = Modifier.align(Alignment.End), + colors = + ButtonDefaults.buttonColors( + containerColor = colors.primary, + contentColor = colors.onPrimary, + ), + onClick = onButtonClicked, + ) { + Text( + stringResource(R.string.hub_onboarding_bottom_sheet_action_button), + style = MaterialTheme.typography.labelLarge, + ) + } + } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt index c55a3fdfc6c0..478970f4e210 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt @@ -45,6 +45,7 @@ import com.android.systemui.keyguard.ui.composable.section.StatusBarSection import com.android.systemui.keyguard.ui.composable.section.TopAreaSection import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel import com.android.systemui.res.R +import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiAod import java.util.Optional import javax.inject.Inject import kotlin.math.roundToInt @@ -128,11 +129,14 @@ constructor( with(notificationSection) { if (!isShadeLayoutWide && !isBypassEnabled) { Box(modifier = Modifier.weight(weight = 1f)) { - AodNotificationIcons( - modifier = - Modifier.align(alignment = Alignment.TopStart) - .padding(start = aodIconPadding) - ) + Column(Modifier.align(alignment = Alignment.TopStart)) { + if (PromotedNotificationUiAod.isEnabled) { + AodPromotedNotification() + } + AodNotificationIcons( + modifier = Modifier.padding(start = aodIconPadding) + ) + } Notifications( areNotificationsVisible = areNotificationsVisible, isShadeLayoutWide = false, @@ -140,9 +144,14 @@ constructor( ) } } else { - AodNotificationIcons( - modifier = Modifier.padding(start = aodIconPadding) - ) + Column { + if (PromotedNotificationUiAod.isEnabled) { + AodPromotedNotification() + } + AodNotificationIcons( + modifier = Modifier.padding(start = aodIconPadding) + ) + } } } if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt index 0ff567bf90ad..d8b3f742b447 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt @@ -19,12 +19,11 @@ package com.android.systemui.keyguard.ui.composable.section import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource -import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ContentScope import com.android.systemui.keyguard.ui.viewmodel.KeyguardMediaViewModel +import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.media.controls.ui.composable.MediaCarousel import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.view.MediaHost @@ -38,7 +37,7 @@ class MediaCarouselSection constructor( private val mediaCarouselController: MediaCarouselController, @param:Named(MediaModule.KEYGUARD) private val mediaHost: MediaHost, - private val keyguardMediaViewModel: KeyguardMediaViewModel, + private val keyguardMediaViewModelFactory: KeyguardMediaViewModel.Factory, ) { @Composable @@ -46,7 +45,10 @@ constructor( isShadeLayoutWide: Boolean, modifier: Modifier = Modifier, ) { - val isMediaVisible by keyguardMediaViewModel.isMediaVisible.collectAsStateWithLifecycle() + val viewModel = + rememberViewModel(traceName = "KeyguardMediaCarousel") { + keyguardMediaViewModelFactory.create() + } val horizontalPadding = if (isShadeLayoutWide) { dimensionResource(id = R.dimen.notification_side_paddings) @@ -55,7 +57,7 @@ constructor( dimensionResource(id = R.dimen.notification_panel_margin_horizontal) } MediaCarousel( - isVisible = isMediaVisible, + isVisible = viewModel.isMediaVisible, mediaHost = mediaHost, modifier = modifier.fillMaxWidth().padding(horizontal = horizontalPadding), carouselController = mediaCarouselController, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt index 2bc392d386bf..b66690c2fe89 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt @@ -53,6 +53,8 @@ import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDi import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder import com.android.systemui.statusbar.notification.icon.ui.viewbinder.StatusBarIconViewBindingFailureTracker import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel +import com.android.systemui.statusbar.notification.promoted.AODPromotedNotification +import com.android.systemui.statusbar.notification.promoted.ui.viewmodel.AODPromotedNotificationViewModel import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer @@ -84,6 +86,7 @@ constructor( private val iconBindingFailureTracker: StatusBarIconViewBindingFailureTracker, private val nicAodViewModel: NotificationIconContainerAlwaysOnDisplayViewModel, private val nicAodIconViewStore: AlwaysOnDisplayNotificationIconViewStore, + private val aodPromotedNotificationViewModelFactory: AODPromotedNotificationViewModel.Factory, private val systemBarUtilsState: SystemBarUtilsState, private val clockInteractor: KeyguardClockInteractor, ) { @@ -107,6 +110,11 @@ constructor( } @Composable + fun AodPromotedNotification() { + AODPromotedNotification(aodPromotedNotificationViewModelFactory) + } + + @Composable fun AodNotificationIcons(modifier: Modifier = Modifier) { val isVisible by keyguardRootViewModel.isNotifIconContainerVisible.collectAsStateWithLifecycle() diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt index 9eb1f68dd669..931134795a53 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt @@ -41,9 +41,10 @@ import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.ui.composable.Overlay -import com.android.systemui.shade.ui.composable.CollapsedShadeHeader import com.android.systemui.shade.ui.composable.OverlayShade +import com.android.systemui.shade.ui.composable.OverlayShadeHeader import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy +import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView import com.android.systemui.statusbar.phone.ui.StatusBarIconController import com.android.systemui.statusbar.phone.ui.TintedIconManager @@ -60,6 +61,8 @@ constructor( private val tintedIconManagerFactory: TintedIconManager.Factory, private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory, private val statusBarIconController: StatusBarIconController, + private val notificationIconContainerStatusBarViewBinder: + NotificationIconContainerStatusBarViewBinder, private val shadeSession: SaveableSession, private val stackScrollView: Lazy<NotificationScrollView>, private val clockSection: DefaultClockSection, @@ -79,7 +82,6 @@ constructor( @Composable override fun ContentScope.Content(modifier: Modifier) { - val notificationStackPadding = dimensionResource(id = R.dimen.notification_side_paddings) val viewModel = @@ -92,26 +94,29 @@ constructor( } OverlayShade( + isShadeLayoutWide = viewModel.isShadeLayoutWide, panelAlignment = Alignment.TopStart, modifier = modifier, onScrimClicked = viewModel::onScrimClicked, + header = { + OverlayShadeHeader( + viewModelFactory = viewModel.shadeHeaderViewModelFactory, + createTintedIconManager = tintedIconManagerFactory::create, + createBatteryMeterViewController = batteryMeterViewControllerFactory::create, + statusBarIconController = statusBarIconController, + notificationIconContainerStatusBarViewBinder = + notificationIconContainerStatusBarViewBinder, + modifier = + Modifier.element(NotificationsShade.Elements.StatusBar) + .layoutId(SingleShadeMeasurePolicy.LayoutId.ShadeHeader), + ) + }, ) { Box { Column { if (viewModel.showHeader) { val burnIn = rememberBurnIn(clockInteractor) - CollapsedShadeHeader( - viewModelFactory = viewModel.shadeHeaderViewModelFactory, - createTintedIconManager = tintedIconManagerFactory::create, - createBatteryMeterViewController = - batteryMeterViewControllerFactory::create, - statusBarIconController = statusBarIconController, - modifier = - Modifier.element(NotificationsShade.Elements.StatusBar) - .layoutId(SingleShadeMeasurePolicy.LayoutId.ShadeHeader), - ) - with(clockSection) { SmallClock( burnInParams = burnIn.parameters, @@ -126,16 +131,17 @@ constructor( stackScrollView = stackScrollView.get(), viewModel = placeholderViewModel, maxScrimTop = { 0f }, + shouldPunchHoleBehindScrim = false, stackTopPadding = notificationStackPadding, stackBottomPadding = notificationStackPadding, - shouldPunchHoleBehindScrim = false, shouldFillMaxSize = false, shouldShowScrim = false, supportNestedScrolling = false, modifier = Modifier.fillMaxWidth(), ) } - // Communicates the bottom position of the drawable area within the shade to NSSL. + // Communicates the bottom position of the drawable area within the shade to + // NSSL. NotificationStackCutoffGuideline( stackScrollView = stackScrollView.get(), viewModel = placeholderViewModel, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt index 50bae8a094ad..3ec14a23421c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt @@ -37,6 +37,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.boundsInWindow +import androidx.compose.ui.layout.layoutId import androidx.compose.ui.layout.onPlaced import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp @@ -49,6 +50,7 @@ import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.rememberViewModel +import com.android.systemui.notifications.ui.composable.NotificationsShade import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace import com.android.systemui.qs.composefragment.ui.GridAnchor import com.android.systemui.qs.flags.QsDetailedView @@ -61,8 +63,11 @@ import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayActionsView import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayContentViewModel import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.ui.composable.Overlay -import com.android.systemui.shade.ui.composable.CollapsedShadeHeader import com.android.systemui.shade.ui.composable.OverlayShade +import com.android.systemui.shade.ui.composable.OverlayShadeHeader +import com.android.systemui.shade.ui.composable.QuickSettingsOverlayHeader +import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy +import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView @@ -82,6 +87,8 @@ constructor( private val tintedIconManagerFactory: TintedIconManager.Factory, private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory, private val statusBarIconController: StatusBarIconController, + private val notificationIconContainerStatusBarViewBinder: + NotificationIconContainerStatusBarViewBinder, private val notificationStackScrollView: Lazy<NotificationScrollView>, private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory, ) : Overlay { @@ -108,43 +115,7 @@ constructor( // set the bounds to null when the QuickSettings overlay disappears DisposableEffect(Unit) { onDispose { viewModel.onPanelShapeChanged(null) } } - OverlayShade( - panelAlignment = Alignment.TopEnd, - modifier = modifier, - onScrimClicked = viewModel::onScrimClicked, - ) { - Column( - modifier = - Modifier.onPlaced { coordinates -> - val boundsInWindow = coordinates.boundsInWindow() - val shadeScrimBounds = - ShadeScrimBounds( - left = boundsInWindow.left, - top = boundsInWindow.top, - right = boundsInWindow.right, - bottom = boundsInWindow.bottom, - ) - val shape = - ShadeScrimShape( - bounds = shadeScrimBounds, - topRadius = 0, - bottomRadius = panelCornerRadius, - ) - viewModel.onPanelShapeChanged(shape) - } - ) { - if (viewModel.showHeader) { - CollapsedShadeHeader( - viewModelFactory = viewModel.shadeHeaderViewModelFactory, - createTintedIconManager = tintedIconManagerFactory::create, - createBatteryMeterViewController = - batteryMeterViewControllerFactory::create, - statusBarIconController = statusBarIconController, - ) - } - ShadeBody(viewModel = viewModel.quickSettingsContainerViewModel) - } - + Box(modifier = modifier) { SnoozeableHeadsUpNotificationSpace( stackScrollView = notificationStackScrollView.get(), viewModel = @@ -152,6 +123,58 @@ constructor( notificationsPlaceholderViewModelFactory.create() }, ) + OverlayShade( + isShadeLayoutWide = viewModel.isShadeLayoutWide, + panelAlignment = Alignment.TopEnd, + onScrimClicked = viewModel::onScrimClicked, + header = { + OverlayShadeHeader( + viewModelFactory = viewModel.shadeHeaderViewModelFactory, + createTintedIconManager = tintedIconManagerFactory::create, + createBatteryMeterViewController = + batteryMeterViewControllerFactory::create, + statusBarIconController = statusBarIconController, + notificationIconContainerStatusBarViewBinder = + notificationIconContainerStatusBarViewBinder, + modifier = + Modifier.element(NotificationsShade.Elements.StatusBar) + .layoutId(SingleShadeMeasurePolicy.LayoutId.ShadeHeader), + ) + }, + ) { + ShadeBody( + viewModel = viewModel.quickSettingsContainerViewModel, + modifier = + Modifier.onPlaced { coordinates -> + val boundsInWindow = coordinates.boundsInWindow() + val shadeScrimBounds = + ShadeScrimBounds( + left = boundsInWindow.left, + top = boundsInWindow.top, + right = boundsInWindow.right, + bottom = boundsInWindow.bottom, + ) + val shape = + ShadeScrimShape( + bounds = shadeScrimBounds, + topRadius = 0, + bottomRadius = panelCornerRadius, + ) + viewModel.onPanelShapeChanged(shape) + }, + header = { + if (viewModel.isShadeLayoutWide) { + QuickSettingsOverlayHeader( + viewModelFactory = viewModel.shadeHeaderViewModelFactory, + createBatteryMeterViewController = + batteryMeterViewControllerFactory::create, + modifier = + Modifier.padding(top = QuickSettingsShade.Dimensions.Padding), + ) + } + }, + ) + } } } } @@ -166,7 +189,11 @@ sealed interface ShadeBodyState { } @Composable -fun ContentScope.ShadeBody(viewModel: QuickSettingsContainerViewModel) { +fun ContentScope.ShadeBody( + viewModel: QuickSettingsContainerViewModel, + modifier: Modifier = Modifier, + header: @Composable () -> Unit, +) { val isEditing by viewModel.editModeViewModel.isEditing.collectAsStateWithLifecycle() val tileDetails = if (QsDetailedView.isEnabled) viewModel.detailsViewModel.activeTileDetails else null @@ -185,16 +212,19 @@ fun ContentScope.ShadeBody(viewModel: QuickSettingsContainerViewModel) { EditMode( viewModel = viewModel.editModeViewModel, modifier = - Modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding), + modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding), ) } + ShadeBodyState.TileDetails -> { - TileDetails(viewModel.detailsViewModel) + TileDetails(modifier = modifier, viewModel.detailsViewModel) } + else -> { QuickSettingsLayout( viewModel = viewModel, - modifier = Modifier.sysuiResTag("quick_settings_panel"), + modifier = modifier.sysuiResTag("quick_settings_panel"), + header = header, ) } } @@ -206,6 +236,7 @@ fun ContentScope.ShadeBody(viewModel: QuickSettingsContainerViewModel) { fun ContentScope.QuickSettingsLayout( viewModel: QuickSettingsContainerViewModel, modifier: Modifier = Modifier, + header: @Composable () -> Unit, ) { Column( verticalArrangement = Arrangement.spacedBy(QuickSettingsShade.Dimensions.Padding), @@ -217,6 +248,7 @@ fun ContentScope.QuickSettingsLayout( bottom = QuickSettingsShade.Dimensions.Padding, ), ) { + header() Toolbar( modifier = Modifier.fillMaxWidth().requiredHeight(QuickSettingsShade.Dimensions.ToolbarHeight), diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt index 0ca7a6af01e0..6c0c5c7e49b9 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt @@ -16,6 +16,7 @@ package com.android.systemui.scene.ui.composable +import androidx.compose.foundation.LocalOverscrollFactory import androidx.compose.foundation.gestures.awaitEachGesture import androidx.compose.foundation.gestures.awaitFirstDown import androidx.compose.foundation.layout.Box @@ -44,6 +45,7 @@ import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.observableTransitionState import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState +import com.android.compose.gesture.effect.rememberOffsetOverscrollEffectFactory import com.android.systemui.lifecycle.rememberActivated import com.android.systemui.qs.ui.adapter.QSSceneAdapter import com.android.systemui.qs.ui.composable.QuickSettingsTheme @@ -52,6 +54,7 @@ import com.android.systemui.scene.shared.model.SceneDataSourceDelegator import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.view.SceneJankMonitor import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel +import com.android.systemui.shade.ui.composable.isFullWidthShade import javax.inject.Provider /** @@ -150,6 +153,13 @@ fun SceneContainer( } } + // Overlays use the offset overscroll effect when shown on large screens, otherwise they + // stretch. All scenes use the OffsetOverscrollEffect. + val offsetOverscrollEffectFactory = rememberOffsetOverscrollEffectFactory() + val stretchOverscrollEffectFactory = checkNotNull(LocalOverscrollFactory.current) + val overlayEffectFactory = + if (isFullWidthShade()) stretchOverscrollEffectFactory else offsetOverscrollEffectFactory + // Inflate qsView here so that shade has the correct qqs height in the first measure pass after // rebooting if ( @@ -192,6 +202,7 @@ fun SceneContainer( scene( key = sceneKey, userActions = userActionsByContentKey.getOrDefault(sceneKey, emptyMap()), + effectFactory = offsetOverscrollEffectFactory, ) { // Activate the scene. LaunchedEffect(scene) { scene.activate() } @@ -208,6 +219,7 @@ fun SceneContainer( overlay( key = overlayKey, userActions = userActionsByContentKey.getOrDefault(overlayKey, emptyMap()), + effectFactory = overlayEffectFactory, ) { // Activate the overlay. LaunchedEffect(overlay) { overlay.activate() } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt index ffdf509174d5..fc59d40ec443 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt @@ -20,10 +20,8 @@ package com.android.systemui.shade.ui.composable import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.rememberScrollableState -import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer @@ -44,59 +42,47 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.LowestZIndexContentPicker -import com.android.compose.gesture.effect.rememberOffsetOverscrollEffect import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.systemui.res.R /** Renders a lightweight shade UI container, as an overlay. */ @Composable fun ContentScope.OverlayShade( + isShadeLayoutWide: Boolean, panelAlignment: Alignment, onScrimClicked: () -> Unit, modifier: Modifier = Modifier, + header: @Composable () -> Unit, content: @Composable () -> Unit, ) { - // TODO(b/384653288) This should be removed when b/378470603 is done. - val idleEffect = rememberOffsetOverscrollEffect(Orientation.Vertical) - Box( - modifier - .overscroll(idleEffect) - .nestedScroll( - remember { - object : NestedScrollConnection { - override suspend fun onPreFling(available: Velocity): Velocity { - return available - } - } - } - ) - .scrollable(rememberScrollableState { 0f }, Orientation.Vertical, idleEffect) - ) { + Box(modifier) { Scrim(onClicked = onScrimClicked) Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = panelAlignment) { Panel( + isShadeLayoutWide = isShadeLayoutWide, modifier = - Modifier.element(OverlayShade.Elements.Panel) - .overscroll(verticalOverscrollEffect) + Modifier.overscroll(verticalOverscrollEffect) + .element(OverlayShade.Elements.Panel) .panelSize(), + header = header, content = content, ) } + + if (isShadeLayoutWide) { + header() + } } } @@ -113,7 +99,12 @@ private fun ContentScope.Scrim(onClicked: () -> Unit, modifier: Modifier = Modif } @Composable -private fun ContentScope.Panel(modifier: Modifier = Modifier, content: @Composable () -> Unit) { +private fun ContentScope.Panel( + isShadeLayoutWide: Boolean, + modifier: Modifier = Modifier, + header: @Composable () -> Unit, + content: @Composable () -> Unit, +) { Box(modifier = modifier.clip(OverlayShade.Shapes.RoundedCornerPanel)) { Spacer( modifier = @@ -125,17 +116,22 @@ private fun ContentScope.Panel(modifier: Modifier = Modifier, content: @Composab ) ) - // This content is intentionally rendered as a separate element from the background in order - // to allow for more flexibility when defining transitions. - content() + Column { + if (!isShadeLayoutWide) { + header() + } + + // This content is intentionally rendered as a separate element from the background in + // order to allow for more flexibility when defining transitions. + content() + } } } @Composable private fun Modifier.panelSize(): Modifier { - val widthSizeClass = LocalWindowSizeClass.current.widthSizeClass return this.then( - if (widthSizeClass == WindowWidthSizeClass.Compact) { + if (isFullWidthShade()) { Modifier.fillMaxWidth() } else { Modifier.width(dimensionResource(id = R.dimen.shade_panel_width)) @@ -144,6 +140,12 @@ private fun Modifier.panelSize(): Modifier { } @Composable +@ReadOnlyComposable +internal fun isFullWidthShade(): Boolean { + return LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Compact +} + +@Composable private fun Modifier.panelPadding(): Modifier { val widthSizeClass = LocalWindowSizeClass.current.widthSizeClass val systemBars = WindowInsets.systemBarsIgnoringVisibility diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt index 3131b539c6af..c5d28adce601 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.interaction.collectIsHoveredAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer @@ -38,11 +39,11 @@ import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ColorScheme import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -50,6 +51,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.Layout +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.Constraints @@ -65,7 +67,6 @@ import com.android.compose.animation.scene.ValueKey import com.android.compose.animation.scene.animateElementFloatAsState import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.modifiers.thenIf -import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.settingslib.Utils import com.android.systemui.battery.BatteryMeterView import com.android.systemui.battery.BatteryMeterViewController @@ -77,10 +78,15 @@ import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.privacy.OngoingPrivacyChip import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.chipBackground +import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.chipHighlighted import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.onScrimDim import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.CollapsedHeight import com.android.systemui.shade.ui.composable.ShadeHeader.Values.ClockScale import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel +import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder +import com.android.systemui.statusbar.phone.NotificationIconContainer import com.android.systemui.statusbar.phone.StatusBarLocation import com.android.systemui.statusbar.phone.StatusIconContainer import com.android.systemui.statusbar.phone.ui.StatusBarIconController @@ -88,6 +94,7 @@ import com.android.systemui.statusbar.phone.ui.TintedIconManager import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel import com.android.systemui.statusbar.policy.Clock +import kotlinx.coroutines.launch object ShadeHeader { object Elements { @@ -114,6 +121,12 @@ object ShadeHeader { val ColorScheme.onScrimDim: Color get() = Color.DarkGray + + val ColorScheme.chipBackground: Color + get() = Color.DarkGray + + val ColorScheme.chipHighlighted: Color + get() = Color.LightGray } object TestTags { @@ -121,6 +134,7 @@ object ShadeHeader { } } +/** The status bar that appears above the Shade scene on small screens */ @Composable fun ContentScope.CollapsedShadeHeader( viewModelFactory: ShadeHeaderViewModel.Factory, @@ -131,9 +145,6 @@ fun ContentScope.CollapsedShadeHeader( ) { val viewModel = rememberViewModel("CollapsedShadeHeader") { viewModelFactory.create() } - val cutoutWidth = LocalDisplayCutout.current.width() - val cutoutHeight = LocalDisplayCutout.current.height() - val cutoutTop = LocalDisplayCutout.current.top val cutoutLocation = LocalDisplayCutout.current.location val horizontalPadding = max(LocalScreenCornerRadius.current / 2f, Shade.Dimensions.HorizontalPadding) @@ -146,123 +157,73 @@ fun ContentScope.CollapsedShadeHeader( } } - val isLargeScreenLayout = - LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Medium || - LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Expanded + val isShadeLayoutWide = viewModel.isShadeLayoutWide val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle() // This layout assumes it is globally positioned at (0, 0) and is the // same size as the screen. - Layout( + CutoutAwareShadeHeader( modifier = modifier.sysuiResTag(ShadeHeader.TestTags.Root), - contents = - listOf( - { - Row(modifier = Modifier.padding(horizontal = horizontalPadding)) { - Clock( - scale = 1f, + startContent = { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(5.dp), + modifier = Modifier.padding(horizontal = horizontalPadding), + ) { + Clock(scale = 1f, viewModel = viewModel) + VariableDayDate( + viewModel = viewModel, + modifier = Modifier.element(ShadeHeader.Elements.CollapsedContentStart), + ) + } + }, + endContent = { + if (isPrivacyChipVisible) { + Box( + modifier = + Modifier.height(CollapsedHeight) + .fillMaxWidth() + .padding(horizontal = horizontalPadding) + ) { + PrivacyChip( + viewModel = viewModel, + modifier = Modifier.align(Alignment.CenterEnd), + ) + } + } else { + Row( + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically, + modifier = + Modifier.element(ShadeHeader.Elements.CollapsedContentEnd) + .padding(horizontal = horizontalPadding), + ) { + if (isShadeLayoutWide) { + ShadeCarrierGroup(viewModel = viewModel) + } + SystemIconChip(viewModel = viewModel, isClickable = isShadeLayoutWide) { + StatusIcons( viewModel = viewModel, - modifier = Modifier.align(Alignment.CenterVertically), + createTintedIconManager = createTintedIconManager, + statusBarIconController = statusBarIconController, + useExpandedFormat = useExpandedTextFormat, + modifier = Modifier.padding(end = 6.dp).weight(1f, fill = false), ) - Spacer(modifier = Modifier.width(5.dp)) - VariableDayDate( + BatteryIcon( viewModel = viewModel, - modifier = - Modifier.element(ShadeHeader.Elements.CollapsedContentStart) - .align(Alignment.CenterVertically), + createBatteryMeterViewController = createBatteryMeterViewController, + useExpandedFormat = useExpandedTextFormat, + modifier = Modifier.padding(vertical = 8.dp), ) } - }, - { - if (isPrivacyChipVisible) { - Box( - modifier = - Modifier.height(CollapsedHeight) - .fillMaxWidth() - .padding(horizontal = horizontalPadding) - ) { - PrivacyChip( - viewModel = viewModel, - modifier = Modifier.align(Alignment.CenterEnd), - ) - } - } else { - Row( - horizontalArrangement = Arrangement.End, - modifier = - Modifier.element(ShadeHeader.Elements.CollapsedContentEnd) - .padding(horizontal = horizontalPadding), - ) { - if (isLargeScreenLayout) { - ShadeCarrierGroup( - viewModel = viewModel, - modifier = Modifier.align(Alignment.CenterVertically), - ) - } - SystemIconContainer( - viewModel = viewModel, - isClickable = isLargeScreenLayout, - modifier = Modifier.align(Alignment.CenterVertically), - ) { - StatusIcons( - viewModel = viewModel, - createTintedIconManager = createTintedIconManager, - statusBarIconController = statusBarIconController, - useExpandedFormat = useExpandedTextFormat, - modifier = - Modifier.align(Alignment.CenterVertically) - .padding(end = 6.dp) - .weight(1f, fill = false), - ) - BatteryIcon( - createBatteryMeterViewController = - createBatteryMeterViewController, - useExpandedFormat = useExpandedTextFormat, - modifier = Modifier.align(Alignment.CenterVertically), - ) - } - } - } - }, - ), - ) { measurables, constraints -> - check(constraints.hasBoundedWidth) - check(measurables.size == 2) - check(measurables[0].size == 1) - check(measurables[1].size == 1) - - val screenWidth = constraints.maxWidth - val cutoutWidthPx = cutoutWidth.roundToPx() - val height = max(cutoutHeight + (cutoutTop * 2), CollapsedHeight).roundToPx() - val childConstraints = Constraints.fixed((screenWidth - cutoutWidthPx) / 2, height) - - val startMeasurable = measurables[0][0] - val endMeasurable = measurables[1][0] - - val startPlaceable = startMeasurable.measure(childConstraints) - val endPlaceable = endMeasurable.measure(childConstraints) - - layout(screenWidth, height) { - when (cutoutLocation) { - CutoutLocation.NONE, - CutoutLocation.RIGHT -> { - startPlaceable.placeRelative(x = 0, y = 0) - endPlaceable.placeRelative(x = startPlaceable.width, y = 0) - } - CutoutLocation.CENTER -> { - startPlaceable.placeRelative(x = 0, y = 0) - endPlaceable.placeRelative(x = startPlaceable.width + cutoutWidthPx, y = 0) - } - CutoutLocation.LEFT -> { - startPlaceable.placeRelative(x = cutoutWidthPx, y = 0) - endPlaceable.placeRelative(x = startPlaceable.width + cutoutWidthPx, y = 0) } } - } - } + }, + ) } +/** The status bar that appears above the Quick Settings scene on small screens */ @Composable fun ContentScope.ExpandedShadeHeader( viewModelFactory: ShadeHeaderViewModel.Factory, @@ -310,27 +271,24 @@ fun ContentScope.ExpandedShadeHeader( } } Spacer(modifier = Modifier.width(5.dp)) - Row(modifier = Modifier.element(ShadeHeader.Elements.ExpandedContent)) { - VariableDayDate( - viewModel = viewModel, - modifier = Modifier.widthIn(max = 90.dp).align(Alignment.CenterVertically), - ) + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.element(ShadeHeader.Elements.ExpandedContent), + ) { + VariableDayDate(viewModel = viewModel, modifier = Modifier.widthIn(max = 90.dp)) Spacer(modifier = Modifier.weight(1f)) - SystemIconContainer(viewModel = viewModel, isClickable = false) { + SystemIconChip(viewModel = viewModel) { StatusIcons( viewModel = viewModel, createTintedIconManager = createTintedIconManager, statusBarIconController = statusBarIconController, useExpandedFormat = useExpandedFormat, - modifier = - Modifier.align(Alignment.CenterVertically) - .padding(end = 6.dp) - .weight(1f, fill = false), + modifier = Modifier.padding(end = 6.dp).weight(1f, fill = false), ) BatteryIcon( + viewModel = viewModel, useExpandedFormat = useExpandedFormat, createBatteryMeterViewController = createBatteryMeterViewController, - modifier = Modifier.align(Alignment.CenterVertically), ) } } @@ -338,8 +296,183 @@ fun ContentScope.ExpandedShadeHeader( } } +/** + * The status bar that appears above both the Notifications and Quick Settings shade overlays when + * overlay shade is enabled. + */ @Composable -private fun ContentScope.Clock(scale: Float, viewModel: ShadeHeaderViewModel, modifier: Modifier) { +fun ContentScope.OverlayShadeHeader( + viewModelFactory: ShadeHeaderViewModel.Factory, + createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager, + createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController, + statusBarIconController: StatusBarIconController, + notificationIconContainerStatusBarViewBinder: NotificationIconContainerStatusBarViewBinder, + modifier: Modifier = Modifier, +) { + val viewModel = rememberViewModel("OverlayShadeHeader") { viewModelFactory.create() } + + val horizontalPadding = + max(LocalScreenCornerRadius.current / 2f, Shade.Dimensions.HorizontalPadding) + + val isShadeLayoutWide = viewModel.isShadeLayoutWide + + val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle() + + // This layout assumes it is globally positioned at (0, 0) and is the + // same size as the screen. + CutoutAwareShadeHeader( + modifier = modifier.sysuiResTag(ShadeHeader.TestTags.Root), + startContent = { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(horizontal = horizontalPadding), + ) { + if (isShadeLayoutWide) { + Clock( + scale = 1f, + viewModel = viewModel, + modifier = Modifier.padding(horizontal = 4.dp), + ) + Spacer(modifier = Modifier.width(5.dp)) + } + NotificationIconChip(viewModel = viewModel) { + if (isShadeLayoutWide) { + NotificationIcons( + viewModel = viewModel, + notificationIconContainerStatusBarViewBinder = + notificationIconContainerStatusBarViewBinder, + modifier = Modifier.width(IntrinsicSize.Min).height(20.dp), + ) + } else { + VariableDayDate(viewModel = viewModel) + } + } + } + }, + endContent = { + Row( + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(horizontal = horizontalPadding), + ) { + SystemIconChip(viewModel = viewModel, isClickable = true, showBackground = true) { + StatusIcons( + viewModel = viewModel, + createTintedIconManager = createTintedIconManager, + statusBarIconController = statusBarIconController, + useExpandedFormat = false, + highlightable = true, + modifier = Modifier.padding(end = 6.dp).weight(1f, fill = false), + ) + BatteryIcon( + viewModel = viewModel, + createBatteryMeterViewController = createBatteryMeterViewController, + useExpandedFormat = false, + highlightable = true, + ) + } + if (isPrivacyChipVisible) { + Box( + modifier = + Modifier.height(CollapsedHeight) + .fillMaxWidth() + .padding(horizontal = horizontalPadding) + ) { + PrivacyChip( + viewModel = viewModel, + modifier = Modifier.align(Alignment.CenterEnd), + ) + } + } + } + }, + ) +} + +/** The header that appears at the top of the Quick Settings shade overlay. */ +@Composable +fun ContentScope.QuickSettingsOverlayHeader( + viewModelFactory: ShadeHeaderViewModel.Factory, + createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController, + modifier: Modifier = Modifier, +) { + val viewModel = rememberViewModel("QuickSettingsOverlayHeader") { viewModelFactory.create() } + + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = modifier.fillMaxWidth(), + ) { + ShadeCarrierGroup(viewModel = viewModel) + BatteryIcon( + viewModel = viewModel, + createBatteryMeterViewController = createBatteryMeterViewController, + useExpandedFormat = true, + ) + } +} + +/* + * Places startContent and endContent according to the location of the display cutout. + * Assumes it is globally positioned at (0, 0) and the same size as the screen. + */ +@Composable +private fun CutoutAwareShadeHeader( + modifier: Modifier = Modifier, + startContent: @Composable () -> Unit, + endContent: @Composable () -> Unit, +) { + val cutoutWidth = LocalDisplayCutout.current.width() + val cutoutHeight = LocalDisplayCutout.current.height() + val cutoutTop = LocalDisplayCutout.current.top + val cutoutLocation = LocalDisplayCutout.current.location + + Layout( + modifier = modifier.sysuiResTag(ShadeHeader.TestTags.Root), + contents = listOf(startContent, endContent), + ) { measurables, constraints -> + check(constraints.hasBoundedWidth) + check(measurables.size == 2) + check(measurables[0].size == 1) + check(measurables[1].size == 1) + + val screenWidth = constraints.maxWidth + val cutoutWidthPx = cutoutWidth.roundToPx() + val height = max(cutoutHeight + (cutoutTop * 2), CollapsedHeight).roundToPx() + val childConstraints = Constraints.fixed((screenWidth - cutoutWidthPx) / 2, height) + + val startMeasurable = measurables[0][0] + val endMeasurable = measurables[1][0] + + val startPlaceable = startMeasurable.measure(childConstraints) + val endPlaceable = endMeasurable.measure(childConstraints) + + layout(screenWidth, height) { + when (cutoutLocation) { + CutoutLocation.NONE, + CutoutLocation.RIGHT -> { + startPlaceable.placeRelative(x = 0, y = 0) + endPlaceable.placeRelative(x = startPlaceable.width, y = 0) + } + CutoutLocation.CENTER -> { + startPlaceable.placeRelative(x = 0, y = 0) + endPlaceable.placeRelative(x = startPlaceable.width + cutoutWidthPx, y = 0) + } + CutoutLocation.LEFT -> { + startPlaceable.placeRelative(x = cutoutWidthPx, y = 0) + endPlaceable.placeRelative(x = startPlaceable.width + cutoutWidthPx, y = 0) + } + } + } + } +} + +@Composable +private fun ContentScope.Clock( + scale: Float, + viewModel: ShadeHeaderViewModel, + modifier: Modifier = Modifier, +) { val layoutDirection = LocalLayoutDirection.current Element(key = ShadeHeader.Elements.Clock, modifier = modifier) { @@ -374,28 +507,31 @@ private fun ContentScope.Clock(scale: Float, viewModel: ShadeHeaderViewModel, mo @Composable private fun BatteryIcon( + viewModel: ShadeHeaderViewModel, createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController, useExpandedFormat: Boolean, + highlightable: Boolean = false, modifier: Modifier = Modifier, ) { + val localContext = LocalContext.current + val themedContext = + ContextThemeWrapper(localContext, R.style.Theme_SystemUI_QuickSettings_Header) + val primaryColor = + Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimary) + val inverseColor = + Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimaryInverse) + + val isHighlighted = viewModel.highlightQuickSettingsIcons + AndroidView( factory = { context -> val batteryIcon = BatteryMeterView(context, null) batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ON) - val themedContext = - ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings_Header) - val fg = Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimary) - val bg = - Utils.getColorAttrDefaultColor( - themedContext, - android.R.attr.textColorPrimaryInverse, - ) - // [BatteryMeterView.updateColors] is an old method that was built to distinguish // between dual-tone colors and single-tone. The current icon is only single-tone, so // the final [fg] is the only one we actually need - batteryIcon.updateColors(fg, bg, fg) + batteryIcon.updateColors(primaryColor, inverseColor, primaryColor) val batteryMaterViewController = createBatteryMeterViewController(batteryIcon, StatusBarLocation.QS) @@ -414,6 +550,13 @@ private fun BatteryIcon( BatteryMeterView.MODE_ON } ) + if (highlightable) { + if (isHighlighted) { + batteryIcon.updateColors(primaryColor, inverseColor, inverseColor) + } else { + batteryIcon.updateColors(primaryColor, inverseColor, primaryColor) + } + } }, modifier = modifier, ) @@ -446,13 +589,51 @@ private fun ShadeCarrierGroup(viewModel: ShadeHeaderViewModel, modifier: Modifie } @Composable +private fun NotificationIcons( + viewModel: ShadeHeaderViewModel, + notificationIconContainerStatusBarViewBinder: NotificationIconContainerStatusBarViewBinder, + modifier: Modifier = Modifier, +) { + val scope = rememberCoroutineScope() + + val isHighlighted = viewModel.highlightNotificationIcons + + AndroidView( + factory = { context -> + NotificationIconContainer(context, null).also { view -> + view.setOverrideIconColor(true) + scope.launch { + notificationIconContainerStatusBarViewBinder.bindWhileAttached( + view = view, + displayId = context.displayId, + ) + } + } + }, + update = { it.setUseInverseOverrideIconColor(isHighlighted) }, + modifier = modifier, + ) +} + +@Composable private fun ContentScope.StatusIcons( viewModel: ShadeHeaderViewModel, createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager, statusBarIconController: StatusBarIconController, useExpandedFormat: Boolean, + highlightable: Boolean = false, modifier: Modifier = Modifier, ) { + val localContext = LocalContext.current + val themedContext = + ContextThemeWrapper(localContext, R.style.Theme_SystemUI_QuickSettings_Header) + val primaryColor = + Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimary) + val inverseColor = + Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimaryInverse) + + val isHighlighted = viewModel.highlightQuickSettingsIcons + val carrierIconSlots = listOf(stringResource(id = com.android.internal.R.string.status_bar_mobile)) val cameraSlot = stringResource(id = com.android.internal.R.string.status_bar_camera) @@ -466,19 +647,12 @@ private fun ContentScope.StatusIcons( val isLocationIndicationEnabled by viewModel.isLocationIndicationEnabled.collectAsStateWithLifecycle() + val iconContainer = remember { StatusIconContainer(themedContext, null) } + val iconManager = remember { createTintedIconManager(iconContainer, StatusBarLocation.QS) } + AndroidView( factory = { context -> - val themedContext = - ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings_Header) - val iconContainer = StatusIconContainer(themedContext, null) - val iconManager = createTintedIconManager(iconContainer, StatusBarLocation.QS) - iconManager.setTint( - Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimary), - Utils.getColorAttrDefaultColor( - themedContext, - android.R.attr.textColorPrimaryInverse, - ), - ) + iconManager.setTint(primaryColor, inverseColor) statusBarIconController.addIconGroup(iconManager) iconContainer @@ -511,35 +685,87 @@ private fun ContentScope.StatusIcons( iconContainer.removeIgnoredSlot(micSlot) iconContainer.removeIgnoredSlot(locationSlot) } + + if (highlightable) { + if (isHighlighted) { + iconManager.setTint(inverseColor, primaryColor) + } else { + iconManager.setTint(primaryColor, inverseColor) + } + } }, modifier = modifier, ) } @Composable -private fun SystemIconContainer( +private fun NotificationIconChip( viewModel: ShadeHeaderViewModel, - isClickable: Boolean, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit, ) { val interactionSource = remember { MutableInteractionSource() } - val isHovered by interactionSource.collectIsHoveredAsState() + val backgroundColor = + if (viewModel.highlightNotificationIcons) MaterialTheme.colorScheme.chipHighlighted + else MaterialTheme.colorScheme.chipBackground + Box(modifier = modifier) { + Row( + modifier = + Modifier.align(Alignment.CenterStart) + .clickable( + interactionSource = interactionSource, + indication = null, + onClick = { viewModel.onNotificationIconChipClicked() }, + ) + .thenIf(DualShade.isEnabled) { + Modifier.graphicsLayer { + shape = RoundedCornerShape(25.dp) + clip = true + } + .background(backgroundColor) + .padding(horizontal = 8.dp, vertical = 4.dp) + } + ) { + content() + } + } +} + +@Composable +private fun SystemIconChip( + viewModel: ShadeHeaderViewModel, + isClickable: Boolean = false, + showBackground: Boolean = false, + modifier: Modifier = Modifier, + content: @Composable RowScope.() -> Unit, +) { + val interactionSource = remember { MutableInteractionSource() } + val isHovered by interactionSource.collectIsHoveredAsState() val hoverModifier = Modifier.clip(RoundedCornerShape(CollapsedHeight / 4)) .background(MaterialTheme.colorScheme.onScrimDim) + val backgroundColor = + if (viewModel.highlightQuickSettingsIcons) MaterialTheme.colorScheme.chipHighlighted + else MaterialTheme.colorScheme.chipBackground Row( + verticalAlignment = Alignment.CenterVertically, modifier = modifier - .height(CollapsedHeight) - .padding(vertical = CollapsedHeight / 4) + .thenIf(showBackground) { + Modifier.graphicsLayer { + shape = RoundedCornerShape(25.dp) + clip = true + } + .background(backgroundColor) + .padding(horizontal = 8.dp, vertical = 4.dp) + } .thenIf(isClickable) { Modifier.clickable( interactionSource = interactionSource, indication = null, - onClick = { viewModel.onSystemIconContainerClicked() }, + onClick = { viewModel.onSystemIconChipClicked() }, ) } .thenIf(isHovered) { hoverModifier }, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt index 931ff56e56cb..93eca86e15cf 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt @@ -6,17 +6,18 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.shadeHeaderText +import com.android.compose.theme.colorAttr import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel @Composable -fun VariableDayDate( - viewModel: ShadeHeaderViewModel, - modifier: Modifier = Modifier, -) { +fun VariableDayDate(viewModel: ShadeHeaderViewModel, modifier: Modifier = Modifier) { val longerText = viewModel.longerDateText.collectAsStateWithLifecycle() val shorterText = viewModel.shorterDateText.collectAsStateWithLifecycle() + val textColor = + if (viewModel.highlightNotificationIcons) colorAttr(android.R.attr.textColorPrimaryInverse) + else colorAttr(android.R.attr.textColorPrimary) + Layout( contents = listOf( @@ -24,7 +25,7 @@ fun VariableDayDate( Text( text = longerText.value, style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.shadeHeaderText, + color = textColor, maxLines = 1, ) }, @@ -32,7 +33,7 @@ fun VariableDayDate( Text( text = shorterText.value, style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.shadeHeaderText, + color = textColor, maxLines = 1, ) }, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt index f1cc71bc59af..c73656eb1ec5 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModule.kt @@ -16,9 +16,9 @@ package com.android.systemui.volume.panel.component.mediaoutput +import com.android.systemui.volume.panel.component.mediaoutput.domain.MediaOutputAvailabilityCriteria import com.android.systemui.volume.panel.component.mediaoutput.ui.composable.MediaOutputComponent import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents -import com.android.systemui.volume.panel.domain.AlwaysAvailableCriteria import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent import dagger.Binds @@ -39,6 +39,6 @@ interface MediaOutputModule { @IntoMap @StringKey(VolumePanelComponents.MEDIA_OUTPUT) fun bindComponentAvailabilityCriteria( - criteria: AlwaysAvailableCriteria + criteria: MediaOutputAvailabilityCriteria ): ComponentAvailabilityCriteria } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt index 96d68ff03acd..eee27b75a999 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt @@ -18,19 +18,26 @@ package com.android.compose.animation.scene import androidx.activity.BackEventCompat import androidx.activity.compose.PredictiveBackHandler +import androidx.compose.animation.core.AnimationSpec import androidx.compose.animation.core.snap import androidx.compose.foundation.gestures.Orientation import androidx.compose.runtime.Composable +import androidx.compose.ui.util.fastCoerceIn import com.android.compose.animation.scene.UserActionResult.ChangeScene import com.android.compose.animation.scene.UserActionResult.HideOverlay import com.android.compose.animation.scene.UserActionResult.ReplaceByOverlay import com.android.compose.animation.scene.UserActionResult.ShowOverlay -import com.android.compose.animation.scene.transition.animateProgress import com.android.mechanics.ProvidedGestureContext import com.android.mechanics.spec.InputDirection +import kotlin.coroutines.cancellation.CancellationException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch @Composable internal fun PredictiveBackHandler( @@ -93,3 +100,63 @@ private fun UserActionResult.copy( is ReplaceByOverlay -> copy(transitionKey = transitionKey) } } + +private suspend fun <T : ContentKey> animateProgress( + state: MutableSceneTransitionLayoutStateImpl, + animation: SwipeAnimation<T>, + progress: Flow<Float>, + commitSpec: AnimationSpec<Float>?, + cancelSpec: AnimationSpec<Float>?, + animationScope: CoroutineScope? = null, +) { + suspend fun animateOffset(targetContent: T, spec: AnimationSpec<Float>?) { + if (state.transitionState != animation.contentTransition || animation.isAnimatingOffset()) { + return + } + + animation.animateOffset( + initialVelocity = 0f, + targetContent = targetContent, + + // Important: we have to specify a spec that correctly animates *progress* (low + // visibility threshold) and not *offset* (higher visibility threshold). + spec = spec ?: animation.contentTransition.transformationSpec.progressSpec, + ) + } + + coroutineScope { + val collectionJob = launch { + try { + progress.collectLatest { progress -> + // Progress based animation should never overscroll given that the + // absoluteDistance exposed to overscroll builders is always 1f and will not + // lead to any noticeable transformation. + animation.dragOffset = progress.fastCoerceIn(0f, 1f) + } + + // Transition committed. + animateOffset(animation.toContent, commitSpec) + } catch (e: CancellationException) { + // Transition cancelled. + animateOffset(animation.fromContent, cancelSpec) + } + } + + // Start the transition. + animationScope?.launch { startTransition(state, animation, collectionJob) } + ?: startTransition(state, animation, collectionJob) + } +} + +private suspend fun <T : ContentKey> startTransition( + state: MutableSceneTransitionLayoutStateImpl, + animation: SwipeAnimation<T>, + progressCollectionJob: Job, +) { + state.startTransition(animation.contentTransition) + // The transition is done. Cancel the collection in case the transition was finished + // because it was interrupted by another transition. + if (progressCollectionJob.isActive) { + progressCollectionJob.cancel() + } +} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index 184c2a28727b..f6d40eef53a3 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -17,6 +17,9 @@ package com.android.compose.animation.scene import androidx.annotation.FloatRange +import androidx.compose.foundation.LocalOverscrollFactory +import androidx.compose.foundation.OverscrollEffect +import androidx.compose.foundation.OverscrollFactory import androidx.compose.foundation.gestures.Orientation import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect @@ -37,7 +40,6 @@ import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection import com.android.compose.gesture.NestedScrollableBound -import com.android.compose.gesture.effect.ContentOverscrollEffect /** * [SceneTransitionLayout] is a container that automatically animates its content whenever its state @@ -82,12 +84,19 @@ interface SceneTransitionLayoutScope<out CS : ContentScope> { * You can configure [userActions] so that swiping on this layout or navigating back will * transition to a different scene. * + * By default, [verticalOverscrollEffect][ContentScope.verticalOverscrollEffect] and + * [horizontalOverscrollEffect][ContentScope.horizontalOverscrollEffect] of this scene will be + * created using [LocalOverscrollFactory]. You can specify a non-null [effectFactory] to set up + * a custom factory that will be used by this scene and by any calls to + * rememberOverscrollEffect() inside the scene. + * * Important: scene order along the z-axis follows call order. Calling scene(A) followed by * scene(B) will mean that scene B renders after/above scene A. */ fun scene( key: SceneKey, userActions: Map<UserAction, UserActionResult> = emptyMap(), + effectFactory: OverscrollFactory? = null, content: @Composable CS.() -> Unit, ) @@ -108,6 +117,12 @@ interface SceneTransitionLayoutScope<out CS : ContentScope> { * to prevent swipes from reaching other scenes or overlays behind this one. Clicking this * protective layer will close the overlay. * + * By default, [verticalOverscrollEffect][ContentScope.verticalOverscrollEffect] and + * [horizontalOverscrollEffect][ContentScope.horizontalOverscrollEffect] of this overlay will be + * created using [LocalOverscrollFactory]. You can specify a non-null [effectFactory] to set up + * a custom factory that will be used by this content and by any calls to + * rememberOverscrollEffect() inside the content. + * * Important: overlays must be defined after all scenes. Overlay order along the z-axis follows * call order. Calling overlay(A) followed by overlay(B) will mean that overlay B renders * after/above overlay A. @@ -118,6 +133,7 @@ interface SceneTransitionLayoutScope<out CS : ContentScope> { mapOf(Back to UserActionResult.HideOverlay(key)), alignment: Alignment = Alignment.Center, isModal: Boolean = true, + effectFactory: OverscrollFactory? = null, content: @Composable CS.() -> Unit, ) } @@ -262,7 +278,7 @@ interface ContentScope : BaseContentScope { * The overscroll effect applied to the content in the vertical direction. This can be used to * customize how the content behaves when the scene is over scrolled. * - * For example, you can use it with the `Modifier.overscroll()` modifier: + * You should use this effect exactly once with the `Modifier.overscroll()` modifier: * ```kotlin * @Composable * fun ContentScope.MyScene() { @@ -276,26 +292,9 @@ interface ContentScope : BaseContentScope { * } * ``` * - * Or you can read the `overscrollDistance` value directly, if you need some custom overscroll - * behavior: - * ```kotlin - * @Composable - * fun ContentScope.MyScene() { - * Box( - * modifier = Modifier - * .graphicsLayer { - * // Translate half of the overscroll - * translationY = verticalOverscrollEffect.overscrollDistance * 0.5f - * } - * ) { - * // ... your content ... - * } - * } - * ``` - * * @see horizontalOverscrollEffect */ - val verticalOverscrollEffect: ContentOverscrollEffect + val verticalOverscrollEffect: OverscrollEffect /** * The overscroll effect applied to the content in the horizontal direction. This can be used to @@ -303,7 +302,7 @@ interface ContentScope : BaseContentScope { * * @see verticalOverscrollEffect */ - val horizontalOverscrollEffect: ContentOverscrollEffect + val horizontalOverscrollEffect: OverscrollEffect /** * Animate some value at the content level. @@ -746,6 +745,7 @@ internal fun SceneTransitionLayoutForTesting( val density = LocalDensity.current val directionChangeSlop = LocalViewConfiguration.current.touchSlop val layoutDirection = LocalLayoutDirection.current + val defaultEffectFactory = checkNotNull(LocalOverscrollFactory.current) val animationScope = rememberCoroutineScope() val layoutImpl = remember { SceneTransitionLayoutImpl( @@ -761,13 +761,14 @@ internal fun SceneTransitionLayoutForTesting( ancestors = ancestors, lookaheadScope = lookaheadScope, directionChangeSlop = directionChangeSlop, + defaultEffectFactory = defaultEffectFactory, ) .also { onLayoutImpl?.invoke(it) } } // TODO(b/317014852): Move this into the SideEffect {} again once STLImpl.scenes is not a // SnapshotStateMap anymore. - layoutImpl.updateContents(builder, layoutDirection) + layoutImpl.updateContents(builder, layoutDirection, defaultEffectFactory) SideEffect { if (state != layoutImpl.state) { diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt index 16fd5b1e78e6..585da0633131 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt @@ -17,6 +17,7 @@ package com.android.compose.animation.scene import androidx.annotation.VisibleForTesting +import androidx.compose.foundation.OverscrollFactory import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.interaction.MutableInteractionSource @@ -120,6 +121,7 @@ internal class SceneTransitionLayoutImpl( */ internal val ancestors: List<Ancestor> = emptyList(), lookaheadScope: LookaheadScope? = null, + defaultEffectFactory: OverscrollFactory, ) { /** @@ -201,7 +203,7 @@ internal class SceneTransitionLayoutImpl( private val nestedScrollConnection = object : NestedScrollConnection {} init { - updateContents(builder, layoutDirection) + updateContents(builder, layoutDirection, defaultEffectFactory) // DraggableHandlerImpl must wait for the scenes to be initialized, in order to access the // current scene (required for SwipeTransition). @@ -209,14 +211,14 @@ internal class SceneTransitionLayoutImpl( DraggableHandler( layoutImpl = this, orientation = Orientation.Horizontal, - gestureEffectProvider = { content(it).scope.horizontalOverscrollGestureEffect }, + gestureEffectProvider = { content(it).horizontalEffects.gestureEffect }, ) verticalDraggableHandler = DraggableHandler( layoutImpl = this, orientation = Orientation.Vertical, - gestureEffectProvider = { content(it).scope.verticalOverscrollGestureEffect }, + gestureEffectProvider = { content(it).verticalEffects.gestureEffect }, ) // Make sure that the state is created on the same thread (most probably the main thread) @@ -286,6 +288,7 @@ internal class SceneTransitionLayoutImpl( internal fun updateContents( builder: SceneTransitionLayoutScope<InternalContentScope>.() -> Unit, layoutDirection: LayoutDirection, + defaultEffectFactory: OverscrollFactory, ) { // Keep a reference of the current contents. After processing [builder], the contents that // were not configured will be removed. @@ -303,6 +306,7 @@ internal class SceneTransitionLayoutImpl( override fun scene( key: SceneKey, userActions: Map<UserAction, UserActionResult>, + effectFactory: OverscrollFactory?, content: @Composable InternalContentScope.() -> Unit, ) { require(!overlaysDefined) { "all scenes must be defined before overlays" } @@ -313,12 +317,14 @@ internal class SceneTransitionLayoutImpl( val scene = scenes[key] val globalZIndex = Content.calculateGlobalZIndex(parentZIndex, ++zIndex, ancestors.size) + val factory = effectFactory ?: defaultEffectFactory if (scene != null) { // Update an existing scene. scene.content = content scene.userActions = resolvedUserActions scene.zIndex = zIndex.toFloat() scene.globalZIndex = globalZIndex + scene.maybeUpdateEffects(factory) } else { // New scene. scenes[key] = @@ -329,6 +335,7 @@ internal class SceneTransitionLayoutImpl( resolvedUserActions, zIndex.toFloat(), globalZIndex, + factory, ) } } @@ -338,6 +345,7 @@ internal class SceneTransitionLayoutImpl( userActions: Map<UserAction, UserActionResult>, alignment: Alignment, isModal: Boolean, + effectFactory: OverscrollFactory?, content: @Composable (InternalContentScope.() -> Unit), ) { overlaysDefined = true @@ -347,6 +355,7 @@ internal class SceneTransitionLayoutImpl( val resolvedUserActions = resolveUserActions(key, userActions, layoutDirection) val globalZIndex = Content.calculateGlobalZIndex(parentZIndex, ++zIndex, ancestors.size) + val factory = effectFactory ?: defaultEffectFactory if (overlay != null) { // Update an existing overlay. overlay.content = content @@ -355,6 +364,7 @@ internal class SceneTransitionLayoutImpl( overlay.userActions = resolvedUserActions overlay.alignment = alignment overlay.isModal = isModal + overlay.maybeUpdateEffects(factory) } else { // New overlay. overlays[key] = @@ -367,6 +377,7 @@ internal class SceneTransitionLayoutImpl( globalZIndex, alignment, isModal, + factory, ) } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt index 86201a9c0879..b7daaf4075ed 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt @@ -17,13 +17,12 @@ package com.android.compose.animation.scene.content import android.annotation.SuppressLint -import androidx.compose.animation.core.AnimationSpec -import androidx.compose.animation.core.AnimationVector -import androidx.compose.animation.core.TwoWayConverter -import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.LocalOverscrollFactory +import androidx.compose.foundation.OverscrollEffect +import androidx.compose.foundation.OverscrollFactory import androidx.compose.foundation.layout.Box -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf @@ -60,12 +59,10 @@ import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.ValueKey import com.android.compose.animation.scene.animateSharedValueAsState import com.android.compose.animation.scene.effect.GestureEffect -import com.android.compose.animation.scene.effect.VisualEffect import com.android.compose.animation.scene.element import com.android.compose.animation.scene.modifiers.noResizeDuringTransitions import com.android.compose.gesture.NestedScrollControlState import com.android.compose.gesture.NestedScrollableBound -import com.android.compose.gesture.effect.OffsetOverscrollEffect import com.android.compose.gesture.nestedScrollController import com.android.compose.modifiers.thenIf import com.android.compose.ui.graphics.ContainerState @@ -81,11 +78,14 @@ internal sealed class Content( actions: Map<UserAction.Resolved, UserActionResult>, zIndex: Float, globalZIndex: Long, + effectFactory: OverscrollFactory, ) { private val nestedScrollControlState = NestedScrollControlState() internal val scope = ContentScopeImpl(layoutImpl, content = this, nestedScrollControlState) val containerState = ContainerState() + // Important: All fields in this class should be backed by State given that contents are updated + // directly during composition, outside of a SideEffect. var content by mutableStateOf(content) var targetSize by mutableStateOf(IntSize.Zero) var userActions by mutableStateOf(actions) @@ -143,16 +143,26 @@ internal sealed class Content( } } + private var lastFactory by mutableStateOf(effectFactory) + var verticalEffects by mutableStateOf(ContentEffects(effectFactory)) + private set + + var horizontalEffects by mutableStateOf(ContentEffects(effectFactory)) + private set + @SuppressLint("NotConstructor") @Composable fun Content(modifier: Modifier = Modifier) { + // If this content has a custom factory, provide it to the content so that the factory is + // automatically used when calling rememberOverscrollEffect(). Box( modifier .zIndex(zIndex) .approachLayout( isMeasurementApproachInProgress = { layoutImpl.state.isTransitioning() } ) { measurable, constraints -> - // TODO(b/353679003): Use the ModifierNode API to set this *before* the approach + // TODO(b/353679003): Use the ModifierNode API to set this *before* the + // approach // pass is started. targetSize = lookaheadSize val placeable = measurable.measure(constraints) @@ -163,11 +173,26 @@ internal sealed class Content( } .testTag(key.testTag) ) { - scope.content() + CompositionLocalProvider(LocalOverscrollFactory provides lastFactory) { + scope.content() + } } } fun areSwipesAllowed(): Boolean = nestedScrollControlState.isOuterScrollAllowed + + fun maybeUpdateEffects(effectFactory: OverscrollFactory) { + if (effectFactory != lastFactory) { + lastFactory = effectFactory + verticalEffects = ContentEffects(effectFactory) + horizontalEffects = ContentEffects(effectFactory) + } + } +} + +internal class ContentEffects(factory: OverscrollFactory) { + val overscrollEffect = factory.createOverscrollEffect() + val gestureEffect = GestureEffect(overscrollEffect) } internal class ContentScopeImpl( @@ -183,34 +208,11 @@ internal class ContentScopeImpl( override val lookaheadScope: LookaheadScope get() = layoutImpl.lookaheadScope - @OptIn(ExperimentalMaterial3ExpressiveApi::class) - private val animationSpatialSpec = - object : AnimationSpec<Float> { - override fun <V : AnimationVector> vectorize(converter: TwoWayConverter<Float, V>) = - layoutImpl.state.motionScheme.defaultSpatialSpec<Float>().vectorize(converter) - } - - private val _verticalOverscrollEffect = - OffsetOverscrollEffect( - orientation = Orientation.Vertical, - animationScope = layoutImpl.animationScope, - animationSpec = animationSpatialSpec, - ) - - private val _horizontalOverscrollEffect = - OffsetOverscrollEffect( - orientation = Orientation.Horizontal, - animationScope = layoutImpl.animationScope, - animationSpec = animationSpatialSpec, - ) - - val verticalOverscrollGestureEffect = GestureEffect(_verticalOverscrollEffect) - - val horizontalOverscrollGestureEffect = GestureEffect(_horizontalOverscrollEffect) - - override val verticalOverscrollEffect = VisualEffect(_verticalOverscrollEffect) + override val verticalOverscrollEffect: OverscrollEffect + get() = content.verticalEffects.overscrollEffect - override val horizontalOverscrollEffect = VisualEffect(_horizontalOverscrollEffect) + override val horizontalOverscrollEffect: OverscrollEffect + get() = content.horizontalEffects.overscrollEffect override fun Modifier.element(key: ElementKey): Modifier { return element(layoutImpl, content, key) diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt index 300de3f36b1f..4fbca430bc4b 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt @@ -16,6 +16,7 @@ package com.android.compose.animation.scene.content +import androidx.compose.foundation.OverscrollFactory import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue @@ -39,7 +40,8 @@ internal class Overlay( globalZIndex: Long, alignment: Alignment, isModal: Boolean, -) : Content(key, layoutImpl, content, actions, zIndex, globalZIndex) { + effectFactory: OverscrollFactory, +) : Content(key, layoutImpl, content, actions, zIndex, globalZIndex, effectFactory) { var alignment by mutableStateOf(alignment) var isModal by mutableStateOf(isModal) diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt index 275341c7268b..7f57798fb1b3 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt @@ -16,6 +16,7 @@ package com.android.compose.animation.scene.content +import androidx.compose.foundation.OverscrollFactory import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import com.android.compose.animation.scene.InternalContentScope @@ -33,7 +34,8 @@ internal class Scene( actions: Map<UserAction.Resolved, UserActionResult>, zIndex: Float, globalZIndex: Long, -) : Content(key, layoutImpl, content, actions, zIndex, globalZIndex) { + effectFactory: OverscrollFactory, +) : Content(key, layoutImpl, content, actions, zIndex, globalZIndex, effectFactory) { override fun toString(): String { return "Scene(key=$key)" } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/GestureEffect.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/GestureEffect.kt index 2db45aa3dd58..a537c8764b0a 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/GestureEffect.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/GestureEffect.kt @@ -16,14 +16,14 @@ package com.android.compose.animation.scene.effect +import androidx.compose.foundation.OverscrollEffect import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.unit.Velocity -import com.android.compose.gesture.effect.ContentOverscrollEffect /** An overscroll effect that ensures only a single fling animation is triggered. */ -internal class GestureEffect(private val delegate: ContentOverscrollEffect) : - ContentOverscrollEffect by delegate { +internal class GestureEffect(private val delegate: OverscrollEffect) : + OverscrollEffect by delegate { private var shouldFling = false override fun applyToScroll( @@ -51,25 +51,3 @@ internal class GestureEffect(private val delegate: ContentOverscrollEffect) : applyToFling(Velocity.Zero) { Velocity.Zero } } } - -/** - * An overscroll effect that only applies visual effects and does not interfere with the actual - * scrolling or flinging behavior. - */ -internal class VisualEffect(private val delegate: ContentOverscrollEffect) : - ContentOverscrollEffect by delegate { - override fun applyToScroll( - delta: Offset, - source: NestedScrollSource, - performScroll: (Offset) -> Offset, - ): Offset { - return performScroll(delta) - } - - override suspend fun applyToFling( - velocity: Velocity, - performFling: suspend (Velocity) -> Velocity, - ) { - performFling(velocity) - } -} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt deleted file mode 100644 index 819cec712808..000000000000 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transition/Seek.kt +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.compose.animation.scene.transition - -import androidx.annotation.FloatRange -import androidx.compose.animation.core.AnimationSpec -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.ui.util.fastCoerceIn -import com.android.compose.animation.scene.ContentKey -import com.android.compose.animation.scene.MutableSceneTransitionLayoutState -import com.android.compose.animation.scene.MutableSceneTransitionLayoutStateImpl -import com.android.compose.animation.scene.OverlayKey -import com.android.compose.animation.scene.SceneKey -import com.android.compose.animation.scene.SwipeAnimation -import com.android.compose.animation.scene.TransitionKey -import com.android.compose.animation.scene.UserActionResult -import com.android.compose.animation.scene.createSwipeAnimation -import com.android.mechanics.ProvidedGestureContext -import com.android.mechanics.spec.InputDirection -import kotlin.coroutines.cancellation.CancellationException -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch - -/** - * Seek to the given [scene] using [progress]. - * - * This will start a transition from the - * [current scene][MutableSceneTransitionLayoutState.currentScene] to [scene], driven by the - * progress in [progress]. Once [progress] stops emitting, we will animate progress to 1f (using - * [animationSpec]) if it stopped normally or to 0f if it stopped with a - * [kotlin.coroutines.cancellation.CancellationException]. - */ -suspend fun MutableSceneTransitionLayoutState.seekToScene( - scene: SceneKey, - @FloatRange(0.0, 1.0) progress: Flow<Float>, - transitionKey: TransitionKey? = null, - animationSpec: AnimationSpec<Float>? = null, -) { - require(scene != currentScene) { - "seekToScene($scene) has to be called with a different scene than the current scene" - } - - seek(UserActionResult.ChangeScene(scene, transitionKey), progress, animationSpec) -} - -/** - * Seek to show the given [overlay] using [progress]. - * - * This will start a transition to show [overlay] from the - * [current scene][MutableSceneTransitionLayoutState.currentScene], driven by the progress in - * [progress]. Once [progress] stops emitting, we will animate progress to 1f (using - * [animationSpec]) if it stopped normally or to 0f if it stopped with a - * [kotlin.coroutines.cancellation.CancellationException]. - */ -suspend fun MutableSceneTransitionLayoutState.seekToShowOverlay( - overlay: OverlayKey, - @FloatRange(0.0, 1.0) progress: Flow<Float>, - transitionKey: TransitionKey? = null, - animationSpec: AnimationSpec<Float>? = null, -) { - require(overlay in currentOverlays) { - "seekToShowOverlay($overlay) can be called only when the overlay is in currentOverlays" - } - - seek(UserActionResult.ShowOverlay(overlay, transitionKey), progress, animationSpec) -} - -/** - * Seek to hide the given [overlay] using [progress]. - * - * This will start a transition to hide [overlay] to the - * [current scene][MutableSceneTransitionLayoutState.currentScene], driven by the progress in - * [progress]. Once [progress] stops emitting, we will animate progress to 1f (using - * [animationSpec]) if it stopped normally or to 0f if it stopped with a - * [kotlin.coroutines.cancellation.CancellationException]. - */ -suspend fun MutableSceneTransitionLayoutState.seekToHideOverlay( - overlay: OverlayKey, - @FloatRange(0.0, 1.0) progress: Flow<Float>, - transitionKey: TransitionKey? = null, - animationSpec: AnimationSpec<Float>? = null, -) { - require(overlay !in currentOverlays) { - "seekToHideOverlay($overlay) can be called only when the overlay is *not* in " + - "currentOverlays" - } - - seek(UserActionResult.HideOverlay(overlay, transitionKey), progress, animationSpec) -} - -private suspend fun MutableSceneTransitionLayoutState.seek( - result: UserActionResult, - progress: Flow<Float>, - animationSpec: AnimationSpec<Float>?, -) { - val layoutState = - when (this) { - is MutableSceneTransitionLayoutStateImpl -> this - } - - val swipeAnimation = - createSwipeAnimation( - layoutState = layoutState, - result = result, - - // We are animating progress, so distance is always 1f. - distance = 1f, - - // The orientation and isUpOrLeft don't matter here given that they are only used during - // overscroll, which is disabled for progress-based transitions. - orientation = Orientation.Horizontal, - isUpOrLeft = false, - // There is no gesture information available here - animateProgress - // will set the progress as the dragOffset. - gestureContext = ProvidedGestureContext(0f, InputDirection.Max), - ) - - animateProgress( - state = layoutState, - animation = swipeAnimation, - progress = progress, - commitSpec = animationSpec, - cancelSpec = animationSpec, - ) -} - -internal suspend fun <T : ContentKey> animateProgress( - state: MutableSceneTransitionLayoutStateImpl, - animation: SwipeAnimation<T>, - progress: Flow<Float>, - commitSpec: AnimationSpec<Float>?, - cancelSpec: AnimationSpec<Float>?, - animationScope: CoroutineScope? = null, -) { - suspend fun animateOffset(targetContent: T, spec: AnimationSpec<Float>?) { - if (state.transitionState != animation.contentTransition || animation.isAnimatingOffset()) { - return - } - - animation.animateOffset( - initialVelocity = 0f, - targetContent = targetContent, - - // Important: we have to specify a spec that correctly animates *progress* (low - // visibility threshold) and not *offset* (higher visibility threshold). - spec = spec ?: animation.contentTransition.transformationSpec.progressSpec, - ) - } - - coroutineScope { - val collectionJob = launch { - try { - progress.collectLatest { progress -> - // Progress based animation should never overscroll given that the - // absoluteDistance exposed to overscroll builders is always 1f and will not - // lead to any noticeable transformation. - animation.dragOffset = progress.fastCoerceIn(0f, 1f) - } - - // Transition committed. - animateOffset(animation.toContent, commitSpec) - } catch (e: CancellationException) { - // Transition cancelled. - animateOffset(animation.fromContent, cancelSpec) - } - } - - // Start the transition. - animationScope?.launch { startTransition(state, animation, collectionJob) } - ?: startTransition(state, animation, collectionJob) - } -} - -private suspend fun <T : ContentKey> startTransition( - state: MutableSceneTransitionLayoutStateImpl, - animation: SwipeAnimation<T>, - progressCollectionJob: Job, -) { - state.startTransition(animation.contentTransition) - // The transition is done. Cancel the collection in case the transition was finished - // because it was interrupted by another transition. - if (progressCollectionJob.isActive) { - progressCollectionJob.cancel() - } -} diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt index 68e85db2c80b..6b439980cc68 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt @@ -14,11 +14,15 @@ * limitations under the License. */ +@file:OptIn(ExperimentalMaterial3ExpressiveApi::class) + package com.android.compose.animation.scene import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring import androidx.compose.foundation.overscroll +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.MotionScheme import androidx.compose.material3.Text import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset @@ -40,6 +44,7 @@ import com.android.compose.animation.scene.content.state.TransitionState.Compani import com.android.compose.animation.scene.content.state.TransitionState.Transition import com.android.compose.animation.scene.subjects.assertThat import com.android.compose.gesture.NestedDraggable +import com.android.compose.gesture.effect.OffsetOverscrollEffectFactory import com.android.compose.test.MonotonicClockTestScope import com.android.compose.test.runMonotonicClockTest import com.android.mechanics.spec.InputDirection @@ -67,22 +72,25 @@ class DraggableHandlerTest { canChangeScene = { canChangeScene(it) }, ) + val defaultEffectFactory = + OffsetOverscrollEffectFactory(testScope, MotionScheme.standard().defaultSpatialSpec()) + var layoutDirection = LayoutDirection.Rtl set(value) { field = value - layoutImpl.updateContents(scenesBuilder, layoutDirection) + layoutImpl.updateContents(scenesBuilder, layoutDirection, defaultEffectFactory) } var mutableUserActionsA = mapOf(Swipe.Up to SceneB, Swipe.Down to SceneC) set(value) { field = value - layoutImpl.updateContents(scenesBuilder, layoutDirection) + layoutImpl.updateContents(scenesBuilder, layoutDirection, defaultEffectFactory) } var mutableUserActionsB = mapOf(Swipe.Up to SceneC, Swipe.Down to SceneA) set(value) { field = value - layoutImpl.updateContents(scenesBuilder, layoutDirection) + layoutImpl.updateContents(scenesBuilder, layoutDirection, defaultEffectFactory) } private val scenesBuilder: SceneTransitionLayoutScope<ContentScope>.() -> Unit = { @@ -125,6 +133,7 @@ class DraggableHandlerTest { // work well with advanceUntilIdle(), which is used by some tests. animationScope = testScope, directionChangeSlop = directionChangeSlop, + defaultEffectFactory = defaultEffectFactory, ) .apply { setContentsAndLayoutTargetSizeForTest(LAYOUT_SIZE) } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt index 8d0af9b57f2a..f625add0648b 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt @@ -18,6 +18,7 @@ package com.android.compose.animation.scene import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween +import androidx.compose.foundation.LocalOverscrollFactory import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.rememberScrollableState import androidx.compose.foundation.gestures.scrollable @@ -32,6 +33,7 @@ import androidx.compose.foundation.overscroll import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue @@ -72,6 +74,7 @@ import com.android.compose.animation.scene.TestScenes.SceneB import com.android.compose.animation.scene.TestScenes.SceneC import com.android.compose.animation.scene.subjects.assertThat import com.android.compose.gesture.effect.OffsetOverscrollEffect +import com.android.compose.gesture.effect.rememberOffsetOverscrollEffectFactory import com.android.compose.test.assertSizeIsEqualTo import com.android.compose.test.setContentAndCreateMainScope import com.android.compose.test.transition @@ -668,16 +671,20 @@ class ElementTest { rule.setContent { density = LocalDensity.current touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { - scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { - Spacer(Modifier.fillMaxSize()) - } - scene(SceneB) { - Spacer( - Modifier.overscroll(verticalOverscrollEffect) - .fillMaxSize() - .element(TestElements.Foo) - ) + CompositionLocalProvider( + LocalOverscrollFactory provides rememberOffsetOverscrollEffectFactory() + ) { + SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { + scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { + Spacer(Modifier.fillMaxSize()) + } + scene(SceneB) { + Spacer( + Modifier.overscroll(verticalOverscrollEffect) + .fillMaxSize() + .element(TestElements.Foo) + ) + } } } } @@ -724,20 +731,24 @@ class ElementTest { rule.setContent { density = LocalDensity.current touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { - scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { - Spacer( - Modifier.overscroll(verticalOverscrollEffect) - .fillMaxSize() - .element(TestElements.Foo) - ) - } - scene(SceneB) { - Spacer( - Modifier.overscroll(verticalOverscrollEffect) - .fillMaxSize() - .element(TestElements.Bar) - ) + CompositionLocalProvider( + LocalOverscrollFactory provides rememberOffsetOverscrollEffectFactory() + ) { + SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { + scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { + Spacer( + Modifier.overscroll(verticalOverscrollEffect) + .fillMaxSize() + .element(TestElements.Foo) + ) + } + scene(SceneB) { + Spacer( + Modifier.overscroll(verticalOverscrollEffect) + .fillMaxSize() + .element(TestElements.Bar) + ) + } } } } @@ -820,16 +831,20 @@ class ElementTest { rule.setContent { density = LocalDensity.current touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { - scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { - Spacer(Modifier.fillMaxSize()) - } - scene(SceneB) { - Spacer( - Modifier.overscroll(verticalOverscrollEffect) - .element(TestElements.Foo) - .fillMaxSize() - ) + CompositionLocalProvider( + LocalOverscrollFactory provides rememberOffsetOverscrollEffectFactory() + ) { + SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { + scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { + Spacer(Modifier.fillMaxSize()) + } + scene(SceneB) { + Spacer( + Modifier.overscroll(verticalOverscrollEffect) + .element(TestElements.Foo) + .fillMaxSize() + ) + } } } } @@ -875,27 +890,31 @@ class ElementTest { rule.setContent { density = LocalDensity.current touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayout( - state = state, - modifier = Modifier.size(layoutWidth, layoutHeight), + CompositionLocalProvider( + LocalOverscrollFactory provides rememberOffsetOverscrollEffectFactory() ) { - scene(SceneA, userActions = mapOf(Swipe.Down to SceneB)) { - Box( - Modifier - // A scrollable that does not consume the scroll gesture - .scrollable( - state = rememberScrollableState(consumeScrollDelta = { 0f }), - orientation = Orientation.Vertical, - ) - .fillMaxSize() - ) - } - scene(SceneB) { - Spacer( - Modifier.overscroll(verticalOverscrollEffect) - .element(TestElements.Foo) - .fillMaxSize() - ) + SceneTransitionLayout( + state = state, + modifier = Modifier.size(layoutWidth, layoutHeight), + ) { + scene(SceneA, userActions = mapOf(Swipe.Down to SceneB)) { + Box( + Modifier + // A scrollable that does not consume the scroll gesture + .scrollable( + state = rememberScrollableState(consumeScrollDelta = { 0f }), + orientation = Orientation.Vertical, + ) + .fillMaxSize() + ) + } + scene(SceneB) { + Spacer( + Modifier.overscroll(verticalOverscrollEffect) + .element(TestElements.Foo) + .fillMaxSize() + ) + } } } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt index b4b328b14a78..04c762f43907 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt @@ -18,21 +18,29 @@ package com.android.compose.animation.scene import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween +import androidx.compose.foundation.LocalOverscrollFactory +import androidx.compose.foundation.OverscrollEffect +import androidx.compose.foundation.OverscrollFactory import androidx.compose.foundation.ScrollState import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberOverscrollEffect import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.platform.LocalViewConfiguration import androidx.compose.ui.platform.testTag import androidx.compose.ui.test.SemanticsMatcher @@ -47,6 +55,7 @@ import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.test.swipe import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.animation.scene.TestOverlays.OverlayA @@ -884,4 +893,65 @@ class OverlayTest { assertThat(state.transitionState).hasCurrentScene(SceneA) assertThat(state.transitionState).hasCurrentOverlays(OverlayC, OverlayD) } + + @Test + fun effectFactory() { + val effects = mutableSetOf<OverscrollEffect>() + var customFactory by mutableStateOf<OverscrollFactory?>(null) + rule.setContent { + CompositionLocalProvider(LocalOverscrollFactory provides DefaultEffectFactory) { + SceneTransitionLayout( + remember { MutableSceneTransitionLayoutStateForTests(SceneA) } + ) { + scene(SceneA, effectFactory = customFactory) { + val effect = checkNotNull(rememberOverscrollEffect()) + SideEffect { + effects.add(effect) + effects.add(horizontalOverscrollEffect) + effects.add(verticalOverscrollEffect) + } + } + } + } + } + + assertThat(effects.size).isEqualTo(3) + effects.forEach { assertThat(it).isInstanceOf(DefaultEffect::class.java) } + + effects.clear() + customFactory = CustomEffectFactory + rule.waitForIdle() + + assertThat(effects.size).isEqualTo(3) + effects.forEach { assertThat(it).isInstanceOf(CustomEffect::class.java) } + } + + private abstract class NoOpEffect : OverscrollEffect { + override val isInProgress: Boolean = false + + override suspend fun applyToFling( + velocity: Velocity, + performFling: suspend (Velocity) -> Velocity, + ) { + performFling(velocity) + } + + override fun applyToScroll( + delta: Offset, + source: NestedScrollSource, + performScroll: (Offset) -> Offset, + ): Offset = performScroll(delta) + } + + private class DefaultEffect : NoOpEffect() + + private class CustomEffect : NoOpEffect() + + private data object DefaultEffectFactory : OverscrollFactory { + override fun createOverscrollEffect(): OverscrollEffect = DefaultEffect() + } + + private data object CustomEffectFactory : OverscrollFactory { + override fun createOverscrollEffect(): OverscrollEffect = CustomEffect() + } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt index c5e4061e834a..26f3c259dca9 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt @@ -24,18 +24,14 @@ import com.android.compose.animation.scene.TestScenes.SceneB import com.android.compose.animation.scene.TestScenes.SceneC import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.subjects.assertThat -import com.android.compose.animation.scene.transition.seekToScene import com.android.compose.test.TestSceneTransition import com.android.compose.test.runMonotonicClockTest import com.android.compose.test.transition import com.google.common.truth.Truth.assertThat -import kotlin.coroutines.cancellation.CancellationException import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.cancelAndJoin -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.flow.consumeAsFlow import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runCurrent @@ -282,77 +278,6 @@ class SceneTransitionLayoutStateTest { } @Test - fun seekToScene() = runMonotonicClockTest { - val state = MutableSceneTransitionLayoutStateForTests(SceneA) - val progress = Channel<Float>() - - val job = - launch(start = CoroutineStart.UNDISPATCHED) { - state.seekToScene(SceneB, progress.consumeAsFlow()) - } - - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).hasFromScene(SceneA) - assertThat(transition).hasToScene(SceneB) - assertThat(transition).hasProgress(0f) - - // Change progress. - progress.send(0.4f) - assertThat(transition).hasProgress(0.4f) - - // Close the channel normally to confirm the transition. - progress.close() - job.join() - assertThat(state.transitionState).isIdle() - assertThat(state.transitionState).hasCurrentScene(SceneB) - } - - @Test - fun seekToScene_cancelled() = runMonotonicClockTest { - val state = MutableSceneTransitionLayoutStateForTests(SceneA) - val progress = Channel<Float>() - - val job = - launch(start = CoroutineStart.UNDISPATCHED) { - state.seekToScene(SceneB, progress.consumeAsFlow()) - } - - val transition = assertThat(state.transitionState).isSceneTransition() - assertThat(transition).hasFromScene(SceneA) - assertThat(transition).hasToScene(SceneB) - assertThat(transition).hasProgress(0f) - - // Change progress. - progress.send(0.4f) - assertThat(transition).hasProgress(0.4f) - - // Close the channel with a CancellationException to cancel the transition. - progress.close(CancellationException()) - job.join() - assertThat(state.transitionState).isIdle() - assertThat(state.transitionState).hasCurrentScene(SceneA) - } - - @Test - fun seekToScene_interrupted() = runMonotonicClockTest { - val state = MutableSceneTransitionLayoutStateForTests(SceneA) - val progress = Channel<Float>() - - val job = - launch(start = CoroutineStart.UNDISPATCHED) { - state.seekToScene(SceneB, progress.consumeAsFlow()) - } - - assertThat(state.transitionState).isSceneTransition() - - // Start a new transition, interrupting the seek transition. - state.setTargetScene(SceneB, animationScope = this) - - // The previous job is cancelled and does not infinitely collect the progress. - job.join() - } - - @Test fun replacedTransitionIsRemovedFromFinishedTransitions() = runTest { val state = MutableSceneTransitionLayoutStateForTests(SceneA) diff --git a/packages/SystemUI/docs/scene.md b/packages/SystemUI/docs/scene.md index bf15b4feadfb..aa3ac08b972c 100644 --- a/packages/SystemUI/docs/scene.md +++ b/packages/SystemUI/docs/scene.md @@ -68,12 +68,9 @@ file evaluates to `true`. 1. Set a collection of **aconfig flags** to `true` by running the following commands: ```console - $ adb shell device_config override systemui com.android.systemui.keyguard_bottom_area_refactor true - $ adb shell device_config override systemui com.android.systemui.keyguard_wm_state_refactor true - $ adb shell device_config override systemui com.android.systemui.migrate_clocks_to_blueprint true - $ adb shell device_config override systemui com.android.systemui.notification_avalanche_throttle_hun true - $ adb shell device_config override systemui com.android.systemui.predictive_back_sysui true - $ adb shell device_config override systemui com.android.systemui.scene_container true + $ adb shell aflags enable com.android.systemui.keyguard_wm_state_refactor --immediate + $ adb shell aflags enable com.android.systemui.notification_avalanche_throttle_hun --immediate + $ adb shell aflags enable com.android.systemui.scene_container --immediate ``` 2. **Restart** System UI by issuing the following command: ```console @@ -87,19 +84,16 @@ file evaluates to `true`. NOTE: this will be removed proper to the actual release of the framework. - *(b)* Turn on logging and look for the logging statements in `logcat`: - ```console - - # Turn on logging from the framework: + *(b)* look in logcat, see the "Checking if the framework is enabled" section + below. - $ adb shell cmd statusbar echo -b SceneFramework:verbose ### Checking if the framework is enabled Look for the log statements from the framework: ```console -$ adb logcat -v time SceneFramework:* *:S +$ adb logcat -s SceneFramework ``` ### Disabling the framework @@ -107,7 +101,7 @@ $ adb logcat -v time SceneFramework:* *:S To **disable** the framework, simply turn off the main aconfig flag: ```console -$ adb shell device_config put systemui com.android.systemui.scene_container false +$ adb shell aflags unset com.android.systemui.scene_container --immediate ``` ## Defining a scene diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt index 1841d2ea6132..d2b61c0ab745 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt @@ -783,7 +783,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { underTest.reinflateViewFlipper(onViewInflatedCallback) verify(viewFlipperController).clearViews() verify(viewFlipperController) - .asynchronouslyInflateView(any(), any(), onViewInflatedCallbackArgumentCaptor.capture()) + .getSecurityView(any(), any(), onViewInflatedCallbackArgumentCaptor.capture()) onViewInflatedCallbackArgumentCaptor.value.onViewInflated(inputViewController) verify(view).updateSecurityViewFlipper() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java index 7bb6ef1c8895..23e07b185a2e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java @@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; @@ -129,23 +130,40 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { } @Test - public void asynchronouslyInflateView() { - mKeyguardSecurityViewFlipperController.asynchronouslyInflateView(SecurityMode.PIN, - mKeyguardSecurityCallback, null); - verify(mAsyncLayoutInflater).inflate(anyInt(), eq(mView), any( - AsyncLayoutInflater.OnInflateFinishedListener.class)); + public void asynchronouslyInflateView_setNeedsInput() { + mKeyguardSecurityViewFlipperController.clearViews(); + ArgumentCaptor<AsyncLayoutInflater.OnInflateFinishedListener> argumentCaptor = + ArgumentCaptor.forClass(AsyncLayoutInflater.OnInflateFinishedListener.class); + mKeyguardSecurityViewFlipperController.getSecurityView(SecurityMode.PIN, + mKeyguardSecurityCallback, controller -> {}); + verify(mAsyncLayoutInflater).inflate(anyInt(), eq(mView), argumentCaptor.capture()); + argumentCaptor.getValue().onInflateFinished( + LayoutInflater.from(getContext()).inflate(R.layout.keyguard_pin_view, null), + R.layout.keyguard_pin_view, mView); } @Test - public void asynchronouslyInflateView_setNeedsInput() { + public void getSecurityView_multipleInvocations_callsAsyncInflateOnce() { + mKeyguardSecurityViewFlipperController.clearViews(); + // Make 2 calls to get security view + var callback1 = mock(KeyguardSecurityViewFlipperController.OnViewInflatedCallback.class); + var callback2 = mock(KeyguardSecurityViewFlipperController.OnViewInflatedCallback.class); + mKeyguardSecurityViewFlipperController.getSecurityView(SecurityMode.PIN, + mKeyguardSecurityCallback, callback1); + mKeyguardSecurityViewFlipperController.getSecurityView(SecurityMode.PIN, + mKeyguardSecurityCallback, callback2); + + // Verify inflation is called once... ArgumentCaptor<AsyncLayoutInflater.OnInflateFinishedListener> argumentCaptor = ArgumentCaptor.forClass(AsyncLayoutInflater.OnInflateFinishedListener.class); - mKeyguardSecurityViewFlipperController.asynchronouslyInflateView(SecurityMode.PIN, - mKeyguardSecurityCallback, null); verify(mAsyncLayoutInflater).inflate(anyInt(), eq(mView), argumentCaptor.capture()); argumentCaptor.getValue().onInflateFinished( - LayoutInflater.from(getContext()).inflate(R.layout.keyguard_password_view, null), - R.layout.keyguard_password_view, mView); + LayoutInflater.from(getContext()).inflate(R.layout.keyguard_pin_view, null), + R.layout.keyguard_pin_view, mView); + + // ... and both callbacks get invoked + verify(callback1).onViewInflated(mKeyguardInputViewController); + verify(callback2).onViewInflated(mKeyguardInputViewController); } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt index 3f4d3f8ba12a..205f94434970 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt @@ -40,6 +40,7 @@ import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations +import org.mockito.kotlin.clearInvocations @ExperimentalCoroutinesApi @SmallTest @@ -65,11 +66,13 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() { testScope.backgroundScope, displayUtils, ) + testScope.runCurrent() } @Test fun onAnyConfigurationChange_updatesOnUiModeChanged() = testScope.runTest { + clearInvocations(configurationController) val lastAnyConfigurationChange by collectLastValue(underTest.onAnyConfigurationChange) assertThat(lastAnyConfigurationChange).isNull() @@ -85,6 +88,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() { @Test fun onAnyConfigurationChange_updatesOnThemeChanged() = testScope.runTest { + clearInvocations(configurationController) val lastAnyConfigurationChange by collectLastValue(underTest.onAnyConfigurationChange) assertThat(lastAnyConfigurationChange).isNull() @@ -101,7 +105,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() { fun onMovedToDisplays_updatesOnMovedToDisplay() = testScope.runTest { val lastOnMovedToDisplay by collectLastValue(underTest.onMovedToDisplay) - assertThat(lastOnMovedToDisplay).isNull() + assertThat(lastOnMovedToDisplay).isEqualTo(Display.DEFAULT_DISPLAY) val configurationCallback = withArgCaptor { verify(configurationController).addCallback(capture()) @@ -115,6 +119,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() { @Test fun onAnyConfigurationChange_updatesOnConfigChanged() = testScope.runTest { + clearInvocations(configurationController) val lastAnyConfigurationChange by collectLastValue(underTest.onAnyConfigurationChange) assertThat(lastAnyConfigurationChange).isNull() @@ -130,6 +135,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() { @Test fun onResolutionScale_updatesOnConfigurationChange() = testScope.runTest { + clearInvocations(configurationController) val scaleForResolution by collectLastValue(underTest.scaleForResolution) assertThat(scaleForResolution).isEqualTo(displaySizeRatio) @@ -149,6 +155,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() { @Test fun onResolutionScale_nullMaxResolution() = testScope.runTest { + clearInvocations(configurationController) val scaleForResolution by collectLastValue(underTest.scaleForResolution) runCurrent() @@ -203,7 +210,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() { anyInt(), anyInt(), anyInt(), - anyInt() + anyInt(), ) ) .thenReturn(ratio) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt index 1f5e30ca4a0d..0d410cff5ff6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt @@ -88,6 +88,34 @@ class CommunalPrefsRepositoryImplTest : SysuiTestCase() { } @Test + fun isHubOnboardingDismissedValue_byDefault_isFalse() = + testScope.runTest { + val isHubOnboardingDismissed by + collectLastValue(underTest.isHubOnboardingDismissed(MAIN_USER)) + assertThat(isHubOnboardingDismissed).isFalse() + } + + @Test + fun isHubOnboardingDismissedValue_onSet_isTrue() = + testScope.runTest { + val isHubOnboardingDismissed by + collectLastValue(underTest.isHubOnboardingDismissed(MAIN_USER)) + + underTest.setHubOnboardingDismissed(MAIN_USER) + assertThat(isHubOnboardingDismissed).isTrue() + } + + @Test + fun isHubOnboardingDismissedValue_onSetForDifferentUser_isStillFalse() = + testScope.runTest { + val isHubOnboardingDismissed by + collectLastValue(underTest.isHubOnboardingDismissed(MAIN_USER)) + + underTest.setHubOnboardingDismissed(SECONDARY_USER) + assertThat(isHubOnboardingDismissed).isFalse() + } + + @Test fun getSharedPreferences_whenFileRestored() = testScope.runTest { val isCtaDismissed by collectLastValue(underTest.isCtaDismissed(MAIN_USER)) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorTest.kt index 9a92f76f90c6..1fef6932ecca 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorTest.kt @@ -74,6 +74,40 @@ class CommunalPrefsInteractorTest : SysuiTestCase() { assertThat(isCtaDismissed).isFalse() } + @Test + fun setHubOnboardingDismissed_currentUser() = + testScope.runTest { + setSelectedUser(MAIN_USER) + val isHubOnboardingDismissed by collectLastValue(underTest.isHubOnboardingDismissed) + + assertThat(isHubOnboardingDismissed).isFalse() + underTest.setHubOnboardingDismissed(MAIN_USER) + assertThat(isHubOnboardingDismissed).isTrue() + } + + @Test + fun setHubOnboardingDismissed_anotherUser() = + testScope.runTest { + setSelectedUser(MAIN_USER) + val isHubOnboardingDismissed by collectLastValue(underTest.isHubOnboardingDismissed) + + assertThat(isHubOnboardingDismissed).isFalse() + underTest.setHubOnboardingDismissed(SECONDARY_USER) + assertThat(isHubOnboardingDismissed).isFalse() + } + + @Test + fun isHubOnboardingDismissed_userSwitch() = + testScope.runTest { + setSelectedUser(MAIN_USER) + underTest.setHubOnboardingDismissed(MAIN_USER) + val isHubOnboardingDismissed by collectLastValue(underTest.isHubOnboardingDismissed) + + assertThat(isHubOnboardingDismissed).isTrue() + setSelectedUser(SECONDARY_USER) + assertThat(isHubOnboardingDismissed).isFalse() + } + private suspend fun setSelectedUser(user: UserInfo) { with(kosmos.fakeUserRepository) { setUserInfos(listOf(user)) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/HubOnboardingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/HubOnboardingInteractorTest.kt new file mode 100644 index 000000000000..ef25dabb4c7f --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/HubOnboardingInteractorTest.kt @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.domain.interactor + +import android.content.pm.UserInfo +import android.content.pm.UserInfo.FLAG_MAIN +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState +import com.android.compose.animation.scene.SceneKey +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 +import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.data.repository.fakeCommunalPrefsRepository +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.settings.fakeUserTracker +import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.fakeUserRepository +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.MutableStateFlow +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class HubOnboardingInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val sceneInteractor = kosmos.sceneInteractor + + private val underTest: HubOnboardingInteractor by lazy { kosmos.hubOnboardingInteractor } + + @Test + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun setHubOnboardingDismissed() = + kosmos.runTest { + setSelectedUser(MAIN_USER) + val isHubOnboardingDismissed by + collectLastValue(fakeCommunalPrefsRepository.isHubOnboardingDismissed(MAIN_USER)) + + underTest.setHubOnboardingDismissed() + + assertThat(isHubOnboardingDismissed).isTrue() + } + + @Test + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun shouldShowHubOnboarding_falseWhenDismissed() = + kosmos.runTest { + setSelectedUser(MAIN_USER) + val shouldShowHubOnboarding by collectLastValue(underTest.shouldShowHubOnboarding) + + fakeCommunalPrefsRepository.setHubOnboardingDismissed(MAIN_USER) + + assertThat(shouldShowHubOnboarding).isFalse() + } + + @Test + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun shouldShowHubOnboarding_falseWhenNotIdleOnCommunal() = + kosmos.runTest { + setSelectedUser(MAIN_USER) + val shouldShowHubOnboarding by collectLastValue(underTest.shouldShowHubOnboarding) + + assertThat(shouldShowHubOnboarding).isFalse() + } + + @Test + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun shouldShowHubOnboarding_trueWhenIdleOnCommunal() = + kosmos.runTest { + setSelectedUser(MAIN_USER) + val shouldShowHubOnboarding by collectLastValue(underTest.shouldShowHubOnboarding) + + // Change to Communal scene. + setIdleScene(Scenes.Communal) + + assertThat(shouldShowHubOnboarding).isFalse() + } + + @Test + @DisableFlags(FLAG_GLANCEABLE_HUB_V2) + fun shouldShowHubOnboarding_falseWhenFlagDisabled() = + kosmos.runTest { + setSelectedUser(MAIN_USER) + val shouldShowHubOnboarding by collectLastValue(underTest.shouldShowHubOnboarding) + + // Change to Communal scene. + setIdleScene(Scenes.Communal) + + assertThat(shouldShowHubOnboarding).isFalse() + } + + private fun setIdleScene(scene: SceneKey) { + sceneInteractor.changeScene(scene, "test") + val transitionState = + MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(scene)) + sceneInteractor.setTransitionState(transitionState) + } + + private suspend fun setSelectedUser(user: UserInfo) { + with(kosmos.fakeUserRepository) { + setUserInfos(listOf(user)) + setSelectedUserInfo(user) + } + kosmos.fakeUserTracker.set(userInfos = listOf(user), selectedUserIndex = 0) + } + + companion object { + val MAIN_USER = UserInfo(0, "main", FLAG_MAIN) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorTest.kt new file mode 100644 index 000000000000..0df8834618d5 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorTest.kt @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.posturing.domain.interactor + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.posturing.data.repository.fake +import com.android.systemui.communal.posturing.data.repository.posturingRepository +import com.android.systemui.communal.posturing.shared.model.PosturedState +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class PosturingInteractorTest : SysuiTestCase() { + + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + + private val underTest by lazy { kosmos.posturingInteractor } + + @Test + fun testNoDebugOverride() = + kosmos.runTest { + val postured by collectLastValue(underTest.postured) + assertThat(postured).isFalse() + + posturingRepository.fake.setPosturedState(PosturedState.Postured(1f)) + assertThat(postured).isTrue() + } + + @Test + fun testOverriddenByDebugValue() = + kosmos.runTest { + val postured by collectLastValue(underTest.postured) + assertThat(postured).isFalse() + + underTest.setValueForDebug(PosturedState.NotPostured) + posturingRepository.fake.setPosturedState(PosturedState.Postured(1f)) + + // Repository value is overridden by debug value + assertThat(postured).isFalse() + + underTest.setValueForDebug(PosturedState.Unknown) + assertThat(postured).isTrue() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/HubOnboardingViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/HubOnboardingViewModelTest.kt new file mode 100644 index 000000000000..712d26275000 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/HubOnboardingViewModelTest.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.ui.viewmodel + +import android.content.pm.UserInfo +import android.content.pm.UserInfo.FLAG_MAIN +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 +import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.data.repository.fakeCommunalPrefsRepository +import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED +import com.android.systemui.flags.fakeFeatureFlagsClassic +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.lifecycle.activateIn +import com.android.systemui.settings.fakeUserTracker +import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.fakeUserRepository +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@EnableFlags(FLAG_GLANCEABLE_HUB_V2) +@RunWith(AndroidJUnit4::class) +class HubOnboardingViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val underTest: HubOnboardingViewModel by lazy { kosmos.hubOnboardingViewModel } + + @Before + fun setUp() { + kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) + underTest.activateIn(kosmos.testScope) + } + + @Test + fun onDismissed_setsDismissedTrue() = + kosmos.runTest { + setSelectedUser(MAIN_USER) + + val isHubOnboardingDismissed by + collectLastValue(fakeCommunalPrefsRepository.isHubOnboardingDismissed(MAIN_USER)) + + underTest.onDismissed() + + assertThat(isHubOnboardingDismissed).isTrue() + } + + private suspend fun setSelectedUser(user: UserInfo) { + with(kosmos.fakeUserRepository) { + setUserInfos(listOf(user)) + setSelectedUserInfo(user) + } + kosmos.fakeUserTracker.set(userInfos = listOf(user), selectedUserIndex = 0) + } + + companion object { + val MAIN_USER = UserInfo(0, "main", FLAG_MAIN) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt index b3f458821cba..70570f9323f1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt @@ -12,13 +12,14 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.controls.ControlsMetricsLogger import com.android.systemui.controls.controller.ControlInfo import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.res.R import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.utils.SafeIconLoader import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -32,6 +33,7 @@ class TemperatureControlBehaviorTest : SysuiTestCase() { @Mock lateinit var controlsMetricsLogger: ControlsMetricsLogger @Mock lateinit var controlActionCoordinator: ControlActionCoordinator @Mock lateinit var controlsController: ControlsController + @Mock lateinit var safeIconLoader: SafeIconLoader private val fakeSystemClock = FakeSystemClock() private val underTest = TemperatureControlBehavior() @@ -53,6 +55,7 @@ class TemperatureControlBehaviorTest : SysuiTestCase() { controlsMetricsLogger, 0, 0, + safeIconLoader, ) } @@ -61,12 +64,7 @@ class TemperatureControlBehaviorTest : SysuiTestCase() { val controlWithState = ControlWithState( ComponentName("test.pkg", "TestClass"), - ControlInfo( - "test_id", - "test title", - "test subtitle", - DeviceTypes.TYPE_AC_UNIT, - ), + ControlInfo("test_id", "test title", "test subtitle", DeviceTypes.TYPE_AC_UNIT), Control.StatefulBuilder( "", PendingIntent.getActivity( @@ -87,11 +85,11 @@ class TemperatureControlBehaviorTest : SysuiTestCase() { ), 0, 0, - 0 + 0, ) ) .setStatus(Control.STATUS_OK) - .build() + .build(), ) viewHolder.bindData(controlWithState, false) underTest.initialize(viewHolder) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt deleted file mode 100644 index ac06a3b9293c..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.android.systemui.keyguard.data.quickaffordance - -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.FlagsParameterization -import androidx.test.filters.SmallTest -import com.android.systemui.Flags -import com.android.systemui.SysuiTestCase -import com.android.systemui.communal.data.repository.communalSceneRepository -import com.android.systemui.communal.domain.interactor.setCommunalV2Available -import com.android.systemui.communal.domain.interactor.setCommunalV2Enabled -import com.android.systemui.communal.shared.model.CommunalScenes -import com.android.systemui.flags.parameterizeSceneContainerFlag -import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository -import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.collectLastValue -import com.android.systemui.kosmos.runCurrent -import com.android.systemui.kosmos.runTest -import com.android.systemui.scene.data.repository.sceneContainerRepository -import com.android.systemui.scene.shared.model.Scenes -import com.android.systemui.testKosmos -import com.google.common.truth.Truth.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.MockitoAnnotations -import platform.test.runner.parameterized.ParameterizedAndroidJunit4 -import platform.test.runner.parameterized.Parameters - -@SmallTest -@EnableFlags(Flags.FLAG_GLANCEABLE_HUB_V2) -@RunWith(ParameterizedAndroidJunit4::class) -class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : SysuiTestCase() { - private val kosmos = testKosmos() - private val Kosmos.underTest by Kosmos.Fixture { glanceableHubQuickAffordanceConfig } - - init { - mSetFlagsRule.setFlagsParameterization(flags!!) - } - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - - // Access the class immediately so that flows are instantiated. - // GlanceableHubQuickAffordanceConfig accesses StateFlow.value directly so we need the flows - // to start flowing before runCurrent is called in the tests. - kosmos.underTest - } - - @Test - fun lockscreenState_whenGlanceableHubEnabled_returnsVisible() = - kosmos.runTest { - kosmos.setCommunalV2Available(true) - runCurrent() - - val lockScreenState by collectLastValue(underTest.lockScreenState) - - assertThat(lockScreenState) - .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java) - } - - @Test - fun lockscreenState_whenGlanceableHubDisabled_returnsHidden() = - kosmos.runTest { - setCommunalV2Enabled(false) - val lockScreenState by collectLastValue(underTest.lockScreenState) - runCurrent() - - assertThat(lockScreenState) - .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) - } - - @Test - fun lockscreenState_whenGlanceableHubNotAvailable_returnsHidden() = - kosmos.runTest { - // Hub is enabled, but not available. - setCommunalV2Enabled(true) - fakeKeyguardRepository.setKeyguardShowing(false) - val lockScreenState by collectLastValue(underTest.lockScreenState) - runCurrent() - - assertThat(lockScreenState) - .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) - } - - @Test - fun pickerScreenState_whenGlanceableHubEnabled_returnsDefault() = - kosmos.runTest { - setCommunalV2Enabled(true) - runCurrent() - - assertThat(underTest.getPickerScreenState()) - .isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default()) - } - - @Test - fun pickerScreenState_whenGlanceableHubDisabled_returnsDisabled() = - kosmos.runTest { - setCommunalV2Enabled(false) - runCurrent() - - assertThat( - underTest.getPickerScreenState() - is KeyguardQuickAffordanceConfig.PickerScreenState.Disabled - ) - } - - @Test - @DisableFlags(Flags.FLAG_SCENE_CONTAINER) - fun onTriggered_changesSceneToCommunal() = - kosmos.runTest { - underTest.onTriggered(expandable = null) - runCurrent() - - assertThat(kosmos.communalSceneRepository.currentScene.value) - .isEqualTo(CommunalScenes.Communal) - } - - @Test - @EnableFlags(Flags.FLAG_SCENE_CONTAINER) - fun testTransitionToGlanceableHub_sceneContainer() = - kosmos.runTest { - underTest.onTriggered(expandable = null) - runCurrent() - - assertThat(kosmos.sceneContainerRepository.currentScene.value) - .isEqualTo(Scenes.Communal) - } - - companion object { - @JvmStatic - @Parameters(name = "{0}") - fun getParams(): List<FlagsParameterization> { - return parameterizeSceneContainerFlag() - } - } -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt index 7c694b4fc95b..810ca4960a57 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt @@ -29,6 +29,7 @@ import com.android.systemui.keyguard.ui.view.KeyguardRootView import com.android.systemui.keyguard.ui.view.layout.sections.AccessibilityActionsSection import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection +import com.android.systemui.keyguard.ui.view.layout.sections.AodPromotedNotificationSection import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection @@ -68,6 +69,7 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() { @Mock private lateinit var defaultStatusBarViewSection: DefaultStatusBarSection @Mock private lateinit var defaultNSSLSection: DefaultNotificationStackScrollLayoutSection @Mock private lateinit var splitShadeGuidelines: SplitShadeGuidelines + @Mock private lateinit var aodPromotedNotificationSection: AodPromotedNotificationSection @Mock private lateinit var aodNotificationIconsSection: AodNotificationIconsSection @Mock private lateinit var aodBurnInSection: AodBurnInSection @Mock private lateinit var clockSection: ClockSection @@ -90,6 +92,7 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() { defaultSettingsPopupMenuSection, defaultStatusBarViewSection, defaultNSSLSection, + aodPromotedNotificationSection, aodNotificationIconsSection, aodBurnInSection, clockSection, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt index ade7614ae853..83b821619659 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt @@ -80,7 +80,7 @@ class AlternateBouncerToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() fun notifications_areFullyVisible_whenShadeIsOpen() = testScope.runTest { val values by collectValues(underTest.notificationAlpha) - kosmos.bouncerWindowBlurTestUtil.shadeExpanded(true) + kosmos.keyguardWindowBlurTestUtil.shadeExpanded(true) keyguardTransitionRepository.sendTransitionSteps( listOf( @@ -100,9 +100,9 @@ class AlternateBouncerToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() fun blurRadiusGoesToMaximumWhenShadeIsExpanded() = testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.shadeExpanded(true) + kosmos.keyguardWindowBlurTestUtil.shadeExpanded(true) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0f, 0f, 0.1f, 0.2f, 0.3f, 1f), startValue = kosmos.blurConfig.maxBlurRadiusPx, endValue = kosmos.blurConfig.maxBlurRadiusPx, @@ -119,9 +119,9 @@ class AlternateBouncerToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() testScope.runTest { val values by collectValues(underTest.notificationBlurRadius) - kosmos.bouncerWindowBlurTestUtil.shadeExpanded(true) + kosmos.keyguardWindowBlurTestUtil.shadeExpanded(true) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0f, 0f, 0.1f, 0.2f, 0.3f, 1f), startValue = kosmos.blurConfig.maxBlurRadiusPx / 3.0f, endValue = kosmos.blurConfig.maxBlurRadiusPx / 3.0f, @@ -135,9 +135,9 @@ class AlternateBouncerToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() fun blurRadiusGoesFromMinToMaxWhenShadeIsNotExpanded() = testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.shadeExpanded(false) + kosmos.keyguardWindowBlurTestUtil.shadeExpanded(false) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0f, 0f, 0.1f, 0.2f, 0.3f, 1f), startValue = kosmos.blurConfig.minBlurRadiusPx, endValue = kosmos.blurConfig.maxBlurRadiusPx, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerTransitionViewModelTest.kt index d782d1e2612c..01191cca87a1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerTransitionViewModelTest.kt @@ -51,7 +51,7 @@ class AodToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.0f, 0.3f, 0.4f, 0.5f, 1.0f), startValue = kosmos.blurConfig.maxBlurRadiusPx, endValue = kosmos.blurConfig.maxBlurRadiusPx, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt index 4d58f7ab118e..28410d9e3be1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt @@ -81,7 +81,7 @@ class DozingToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), startValue = kosmos.blurConfig.minBlurRadiusPx, endValue = kosmos.blurConfig.maxBlurRadiusPx, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt index 88fd333b34a8..abf8b39ce5af 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt @@ -45,7 +45,7 @@ class GlanceableHubToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), startValue = kosmos.blurConfig.maxBlurRadiusPx, endValue = kosmos.blurConfig.maxBlurRadiusPx, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelTest.kt new file mode 100644 index 000000000000..38829da69c28 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelTest.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.data.repository.keyguardRepository +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.lifecycle.activateIn +import com.android.systemui.media.controls.data.repository.mediaFilterRepository +import com.android.systemui.media.controls.shared.model.MediaData +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class KeyguardMediaViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + + private val underTest = kosmos.keyguardMediaViewModelFactory.create() + + @Before + fun setUp() { + underTest.activateIn(kosmos.testScope) + } + + @Test + fun onDozing_noActiveMedia_mediaIsHidden() = + kosmos.runTest { + keyguardRepository.setIsDozing(true) + + assertThat(underTest.isMediaVisible).isFalse() + } + + @Test + fun onDozing_activeMediaExists_mediaIsHidden() = + kosmos.runTest { + val userMedia = MediaData(active = true) + + mediaFilterRepository.addSelectedUserMediaEntry(userMedia) + keyguardRepository.setIsDozing(true) + + assertThat(underTest.isMediaVisible).isFalse() + } + + @Test + fun onDeviceAwake_activeMediaExists_mediaIsVisible() = + kosmos.runTest { + val userMedia = MediaData(active = true) + + mediaFilterRepository.addSelectedUserMediaEntry(userMedia) + keyguardRepository.setIsDozing(false) + + assertThat(underTest.isMediaVisible).isTrue() + } + + @Test + fun onDeviceAwake_noActiveMedia_mediaIsHidden() = + kosmos.runTest { + keyguardRepository.setIsDozing(false) + + assertThat(underTest.isMediaVisible).isFalse() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerWindowBlurTestUtilKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardWindowBlurTestUtilKosmos.kt index cde853140de2..ef07786284c9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerWindowBlurTestUtilKosmos.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardWindowBlurTestUtilKosmos.kt @@ -33,9 +33,9 @@ import com.android.systemui.shade.shadeTestUtil import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.TestScope -val Kosmos.bouncerWindowBlurTestUtil by +val Kosmos.keyguardWindowBlurTestUtil by Kosmos.Fixture { - BouncerWindowBlurTestUtil( + KeyguardWindowBlurTestUtil( shadeTestUtil = shadeTestUtil, fakeKeyguardTransitionRepository = fakeKeyguardTransitionRepository, fakeKeyguardRepository = fakeKeyguardRepository, @@ -43,7 +43,7 @@ val Kosmos.bouncerWindowBlurTestUtil by ) } -class BouncerWindowBlurTestUtil( +class KeyguardWindowBlurTestUtil( private val shadeTestUtil: ShadeTestUtil, private val fakeKeyguardTransitionRepository: FakeKeyguardTransitionRepository, private val fakeKeyguardRepository: FakeKeyguardRepository, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt index 914094fa39df..fdee8d0544f0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt @@ -159,9 +159,9 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza fun blurRadiusIsMaxWhenShadeIsExpanded() = testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.shadeExpanded(true) + kosmos.keyguardWindowBlurTestUtil.shadeExpanded(true) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), startValue = kosmos.blurConfig.maxBlurRadiusPx, endValue = kosmos.blurConfig.maxBlurRadiusPx, @@ -176,9 +176,9 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza fun blurRadiusGoesFromMinToMaxWhenShadeIsNotExpanded() = testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.shadeExpanded(false) + kosmos.keyguardWindowBlurTestUtil.shadeExpanded(false) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), startValue = kosmos.blurConfig.minBlurRadiusPx, endValue = kosmos.blurConfig.maxBlurRadiusPx, @@ -193,10 +193,10 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza fun notificationBlur_isNonZero_whenShadeIsExpanded() = testScope.runTest { val values by collectValues(underTest.notificationBlurRadius) - kosmos.bouncerWindowBlurTestUtil.shadeExpanded(true) + kosmos.keyguardWindowBlurTestUtil.shadeExpanded(true) runCurrent() - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0f, 0f, 0.1f, 0.2f, 0.3f, 1f), startValue = kosmos.blurConfig.maxBlurRadiusPx / 3.0f, endValue = kosmos.blurConfig.maxBlurRadiusPx / 3.0f, @@ -212,10 +212,10 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest(flags: FlagsParameteriza fun notifications_areFullyVisible_whenShadeIsExpanded() = testScope.runTest { val values by collectValues(underTest.notificationAlpha) - kosmos.bouncerWindowBlurTestUtil.shadeExpanded(true) + kosmos.keyguardWindowBlurTestUtil.shadeExpanded(true) runCurrent() - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0f, 0f, 0.1f, 0.2f, 0.3f, 1f), startValue = 1.0f, endValue = 1.0f, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModelTest.kt index e11e3076c6c3..6db876756d3a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModelTest.kt @@ -45,7 +45,7 @@ class OccludedToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), startValue = kosmos.blurConfig.maxBlurRadiusPx, endValue = kosmos.blurConfig.maxBlurRadiusPx, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt index 6895794df3dd..aa1e7ae9d509 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt @@ -145,7 +145,7 @@ class PrimaryBouncerToAodTransitionViewModelTest : SysuiTestCase() { testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), startValue = kosmos.blurConfig.maxBlurRadiusPx, endValue = kosmos.blurConfig.minBlurRadiusPx, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt index 4013c700673f..766816b1ac26 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt @@ -128,7 +128,7 @@ class PrimaryBouncerToDozingTransitionViewModelTest : SysuiTestCase() { testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), startValue = kosmos.blurConfig.maxBlurRadiusPx, endValue = kosmos.blurConfig.minBlurRadiusPx, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelTest.kt index f3f4c89688c9..9cfcce43d13d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelTest.kt @@ -45,7 +45,7 @@ class PrimaryBouncerToGlanceableHubTransitionViewModelTest : SysuiTestCase() { testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), startValue = kosmos.blurConfig.minBlurRadiusPx, endValue = kosmos.blurConfig.minBlurRadiusPx, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt index bae49fa14999..0db0c5fe8482 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt @@ -116,9 +116,9 @@ class PrimaryBouncerToLockscreenTransitionViewModelTest : SysuiTestCase() { fun blurRadiusGoesFromMaxToMinWhenShadeIsNotExpanded() = testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.shadeExpanded(false) + kosmos.keyguardWindowBlurTestUtil.shadeExpanded(false) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), startValue = kosmos.blurConfig.maxBlurRadiusPx, endValue = kosmos.blurConfig.minBlurRadiusPx, @@ -131,9 +131,9 @@ class PrimaryBouncerToLockscreenTransitionViewModelTest : SysuiTestCase() { fun blurRadiusRemainsAtMaxWhenShadeIsExpanded() = testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.shadeExpanded(true) + kosmos.keyguardWindowBlurTestUtil.shadeExpanded(true) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), startValue = kosmos.blurConfig.maxBlurRadiusPx, endValue = kosmos.blurConfig.maxBlurRadiusPx, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToOccludedTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToOccludedTransitionViewModelTest.kt index 8a2fc56e11e6..b0b4af5fea5b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToOccludedTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToOccludedTransitionViewModelTest.kt @@ -45,7 +45,7 @@ class PrimaryBouncerToOccludedTransitionViewModelTest : SysuiTestCase() { testScope.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.bouncerWindowBlurTestUtil.assertTransitionToBlurRadius( + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), startValue = kosmos.blurConfig.minBlurRadiusPx, endValue = kosmos.blurConfig.minBlurRadiusPx, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java index 555ba56e087f..7f9313cbeb5b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java @@ -19,6 +19,7 @@ package com.android.systemui.navigationbar.views; import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN; +import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING; import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT; import static android.inputmethodservice.InputMethodService.IME_VISIBLE; import static android.view.Display.DEFAULT_DISPLAY; @@ -30,6 +31,8 @@ import static com.android.systemui.assist.AssistManager.INVOCATION_TYPE_HOME_BUT import static com.android.systemui.navigationbar.views.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS; import static com.android.systemui.navigationbar.views.buttons.KeyButtonView.NavBarButtonEvent.NAVBAR_IME_SWITCHER_BUTTON_LONGPRESS; import static com.android.systemui.navigationbar.views.buttons.KeyButtonView.NavBarButtonEvent.NAVBAR_IME_SWITCHER_BUTTON_TAP; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; import static com.google.common.truth.Truth.assertThat; @@ -487,6 +490,65 @@ public class NavigationBarTest extends SysuiTestCase { verify(mUserTracker).addCallback(any(UserTracker.Callback.class), any(Executor.class)); } + /** + * Verifies that the SysUI state is updated correctly when given a new IME window status with + * IME visible and IME Switcher button visible. + */ + @Test + public void testSetImeWindowStatusSysuiState_ImeVisibleImeSwitcherButtonVisible() { + doNothing().when(mNavigationBar).checkNavBarModes(); + + mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, IME_VISIBLE, + BACK_DISPOSITION_DEFAULT, true /* showImeSwitcher */); + verify(mMockSysUiState).setFlag(eq(SYSUI_STATE_IME_SHOWING), eq(true)); + verify(mMockSysUiState).setFlag(eq(SYSUI_STATE_IME_SWITCHER_SHOWING), eq(true)); + } + + /** + * Verifies that the SysUI state is updated correctly when given a new IME window status with + * IME visible and IME Switcher button not visible. + */ + @Test + public void testSetImeWindowStatusSysuiState_ImeVisibleImeSwitcherButtonNotVisible() { + doNothing().when(mNavigationBar).checkNavBarModes(); + + mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, IME_VISIBLE, + BACK_DISPOSITION_DEFAULT, false /* showImeSwitcher */); + verify(mMockSysUiState).setFlag(eq(SYSUI_STATE_IME_SHOWING), eq(true)); + verify(mMockSysUiState).setFlag(eq(SYSUI_STATE_IME_SWITCHER_SHOWING), eq(false)); + } + + /** + * Verifies that the SysUI state is updated correctly when given a new IME window status with + * IME not visible and IME Switcher button visible. + */ + @Test + public void testSetImeWindowStatusSysuiState_ImeNotVisibleImeSwitcherButtonVisible() { + doNothing().when(mNavigationBar).checkNavBarModes(); + // Set initial state for later reset to be able to take place. + mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, IME_VISIBLE, + BACK_DISPOSITION_DEFAULT, true /* showImeSwitcher */); + + mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, 0 /* vis */, + BACK_DISPOSITION_DEFAULT, true /* showImeSwitcher */); + verify(mMockSysUiState).setFlag(eq(SYSUI_STATE_IME_SHOWING), eq(false)); + verify(mMockSysUiState).setFlag(eq(SYSUI_STATE_IME_SWITCHER_SHOWING), eq(false)); + } + + /** + * Verifies that the SysUI state is updated correctly when given a new IME window status with + * IME visible and back disposition adjust nothing. + */ + @Test + public void testSetImeWindowStatusSysuiState_ImeVisibleBackDispositionAdjustNothing() { + doNothing().when(mNavigationBar).checkNavBarModes(); + + mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, IME_VISIBLE, + BACK_DISPOSITION_ADJUST_NOTHING, true /* showImeSwitcher */); + verify(mMockSysUiState).setFlag(eq(SYSUI_STATE_IME_SHOWING), eq(true)); + verify(mMockSysUiState).setFlag(eq(SYSUI_STATE_IME_SWITCHER_SHOWING), eq(true)); + } + @Test public void testSetImeWindowStatusWhenImeSwitchOnDisplay() { // Create default & external NavBar fragment. diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeUserActionsViewModelTest.kt deleted file mode 100644 index 46b02e92a4f9..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeUserActionsViewModelTest.kt +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.notifications.ui.viewmodel - -import android.testing.TestableLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.compose.animation.scene.Swipe -import com.android.compose.animation.scene.UserActionResult -import com.android.systemui.SysuiTestCase -import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository -import com.android.systemui.authentication.shared.model.AuthenticationMethodModel -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository -import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor -import com.android.systemui.flags.EnableSceneContainer -import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor -import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus -import com.android.systemui.kosmos.testScope -import com.android.systemui.lifecycle.activateIn -import com.android.systemui.scene.domain.interactor.sceneInteractor -import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver -import com.android.systemui.scene.shared.model.SceneFamilies -import com.android.systemui.scene.shared.model.Scenes -import com.android.systemui.shade.ui.viewmodel.notificationsShadeUserActionsViewModel -import com.android.systemui.testKosmos -import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.runCurrent -import kotlinx.coroutines.test.runTest -import org.junit.Test -import org.junit.runner.RunWith - -@OptIn(ExperimentalCoroutinesApi::class) -@SmallTest -@RunWith(AndroidJUnit4::class) -@TestableLooper.RunWithLooper -@EnableSceneContainer -class NotificationsShadeUserActionsViewModelTest : SysuiTestCase() { - - private val kosmos = testKosmos() - private val testScope = kosmos.testScope - private val sceneInteractor by lazy { kosmos.sceneInteractor } - private val deviceUnlockedInteractor by lazy { kosmos.deviceUnlockedInteractor } - - private val underTest by lazy { kosmos.notificationsShadeUserActionsViewModel } - - @Test - fun upTransitionSceneKey_deviceLocked_lockscreen() = - testScope.runTest { - val actions by collectLastValue(underTest.actions) - lockDevice() - underTest.activateIn(this) - - assertThat((actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene) - .isEqualTo(SceneFamilies.Home) - assertThat(actions?.get(Swipe.Down)).isNull() - assertThat(kosmos.homeSceneFamilyResolver.resolvedScene.value) - .isEqualTo(Scenes.Lockscreen) - } - - @Test - fun upTransitionSceneKey_deviceLocked_keyguardDisabled_gone() = - testScope.runTest { - val actions by collectLastValue(underTest.actions) - lockDevice() - kosmos.keyguardEnabledInteractor.notifyKeyguardEnabled(false) - underTest.activateIn(this) - - assertThat((actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene) - .isEqualTo(SceneFamilies.Home) - assertThat(kosmos.homeSceneFamilyResolver.resolvedScene.value).isEqualTo(Scenes.Gone) - } - - @Test - fun upTransitionSceneKey_deviceUnlocked_gone() = - testScope.runTest { - val actions by collectLastValue(underTest.actions) - lockDevice() - unlockDevice() - underTest.activateIn(this) - - assertThat((actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene) - .isEqualTo(SceneFamilies.Home) - assertThat(actions?.get(Swipe.Down)).isNull() - assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Gone) - } - - @Test - fun upTransitionSceneKey_authMethodSwipe_lockscreenNotDismissed_goesToLockscreen() = - testScope.runTest { - val actions by collectLastValue(underTest.actions) - kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true) - kosmos.fakeAuthenticationRepository.setAuthenticationMethod( - AuthenticationMethodModel.None - ) - sceneInteractor.changeScene(Scenes.Lockscreen, "reason") - underTest.activateIn(this) - - assertThat((actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene) - .isEqualTo(SceneFamilies.Home) - assertThat(kosmos.homeSceneFamilyResolver.resolvedScene.value) - .isEqualTo(Scenes.Lockscreen) - } - - @Test - fun upTransitionSceneKey_authMethodSwipe_lockscreenDismissed_goesToGone() = - testScope.runTest { - val deviceUnlockStatus by collectLastValue(deviceUnlockedInteractor.deviceUnlockStatus) - val actions by collectLastValue(underTest.actions) - kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true) - kosmos.fakeAuthenticationRepository.setAuthenticationMethod( - AuthenticationMethodModel.None - ) - assertThat(deviceUnlockStatus?.isUnlocked).isTrue() - sceneInteractor // force the lazy; this will kick off StateFlows - runCurrent() - sceneInteractor.changeScene(Scenes.Gone, "reason") - underTest.activateIn(this) - - assertThat((actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene) - .isEqualTo(SceneFamilies.Home) - assertThat(kosmos.homeSceneFamilyResolver.resolvedScene.value).isEqualTo(Scenes.Gone) - } - - private fun TestScope.lockDevice() { - val deviceUnlockStatus by collectLastValue(deviceUnlockedInteractor.deviceUnlockStatus) - - kosmos.fakeAuthenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) - assertThat(deviceUnlockStatus?.isUnlocked).isFalse() - sceneInteractor.changeScene(Scenes.Lockscreen, "reason") - runCurrent() - } - - private fun TestScope.unlockDevice() { - val deviceUnlockStatus by collectLastValue(deviceUnlockedInteractor.deviceUnlockStatus) - - kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( - SuccessFingerprintAuthenticationStatus(0, true) - ) - assertThat(deviceUnlockStatus?.isUnlocked).isTrue() - sceneInteractor.changeScene(Scenes.Gone, "reason") - runCurrent() - } -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt index 3ae7a1672821..3966e1e44de7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt @@ -21,8 +21,10 @@ import com.android.systemui.privacy.PrivacyDialogController import com.android.systemui.privacy.PrivacyDialogControllerV2 import com.android.systemui.privacy.PrivacyItemController import com.android.systemui.privacy.logging.PrivacyLogger +import com.android.systemui.shade.data.repository.shadeDialogContextInteractor import com.android.systemui.statusbar.phone.StatusIconContainer import com.android.systemui.statusbar.policy.DeviceProvisionedController +import com.android.systemui.testKosmos import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -49,6 +51,7 @@ private fun <T> any(): T = Mockito.any<T>() @RunWith(AndroidJUnit4::class) class HeaderPrivacyIconsControllerTest : SysuiTestCase() { + private val kosmos = testKosmos() @Mock private lateinit var privacyItemController: PrivacyItemController @Mock @@ -113,7 +116,8 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() { broadcastDispatcher, safetyCenterManager, deviceProvisionedController, - featureFlags + featureFlags, + kosmos.shadeDialogContextInteractor, ) backgroundExecutor.runAllReady() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt index 3d014b6822b4..a82a7de75cc0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt @@ -34,7 +34,7 @@ import com.android.systemui.scene.data.repository.WindowRootViewVisibilityReposi import com.android.systemui.statusbar.NotificationPresenter import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs -import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor +import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.notification.headsup.HeadsUpManager import com.android.systemui.statusbar.notification.init.NotificationsController import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor @@ -70,8 +70,7 @@ class WindowRootViewVisibilityInteractorTest : SysuiTestCase() { private val notificationsController = mock<NotificationsController>() private val powerInteractor = PowerInteractorFactory.create().powerInteractor private val activeNotificationsRepository = kosmos.activeNotificationListRepository - private val activeNotificationsInteractor = - ActiveNotificationsInteractor(activeNotificationsRepository, testDispatcher) + private val activeNotificationsInteractor = kosmos.activeNotificationsInteractor private val underTest = WindowRootViewVisibilityInteractor( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt index 27e9f07af168..3d5daf6cf9c2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt @@ -318,7 +318,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { val displayId = 1 setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = displayId)) val onSaved = { _: Uri? -> } - focusedDisplayRepository.emit(displayId) + focusedDisplayRepository.setDisplayId(displayId) screenshotExecutor.executeScreenshots( createScreenshotRequest( @@ -345,7 +345,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { display(TYPE_INTERNAL, id = Display.DEFAULT_DISPLAY), display(TYPE_EXTERNAL, id = 1), ) - focusedDisplayRepository.emit(5) // invalid display + focusedDisplayRepository.setDisplayId(5) // invalid display val onSaved = { _: Uri? -> } screenshotExecutor.executeScreenshots( createScreenshotRequest( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt index 007a0fb87953..4f332d4bbed8 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt @@ -17,15 +17,21 @@ package com.android.systemui.shade.data.repository import android.provider.Settings.Global.DEVELOPMENT_SHADE_DISPLAY_AWARENESS +import android.view.Display +import android.view.Display.TYPE_EXTERNAL import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues +import com.android.systemui.display.data.repository.display import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.shade.display.AnyExternalShadeDisplayPolicy import com.android.systemui.shade.display.DefaultDisplayShadePolicy +import com.android.systemui.shade.display.FakeShadeDisplayPolicy import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy import com.android.systemui.testKosmos import com.android.systemui.util.settings.fakeGlobalSettings @@ -37,24 +43,28 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class ShadeDisplaysRepositoryTest : SysuiTestCase() { - private val kosmos = testKosmos() + private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val testScope = kosmos.testScope private val globalSettings = kosmos.fakeGlobalSettings private val displayRepository = kosmos.displayRepository private val defaultPolicy = DefaultDisplayShadePolicy() private val policies = kosmos.shadeDisplayPolicies + private val keyguardRepository = kosmos.fakeKeyguardRepository - private val underTest = + private fun createUnderTest(shadeOnDefaultDisplayWhenLocked: Boolean = false) = ShadeDisplaysRepositoryImpl( globalSettings, defaultPolicy, testScope.backgroundScope, policies, + shadeOnDefaultDisplayWhenLocked = shadeOnDefaultDisplayWhenLocked, + keyguardRepository, ) @Test fun policy_changing_propagatedFromTheLatestPolicy() = testScope.runTest { + val underTest = createUnderTest() val displayIds by collectValues(underTest.displayId) assertThat(displayIds).containsExactly(0) @@ -81,30 +91,54 @@ class ShadeDisplaysRepositoryTest : SysuiTestCase() { @Test fun policy_updatesBasedOnSettingValue_defaultDisplay() = testScope.runTest { - val policy by collectLastValue(underTest.policy) - + val underTest = createUnderTest() globalSettings.putString(DEVELOPMENT_SHADE_DISPLAY_AWARENESS, "default_display") - assertThat(policy).isInstanceOf(DefaultDisplayShadePolicy::class.java) + assertThat(underTest.currentPolicy).isInstanceOf(DefaultDisplayShadePolicy::class.java) } @Test fun policy_updatesBasedOnSettingValue_anyExternal() = testScope.runTest { - val policy by collectLastValue(underTest.policy) - + val underTest = createUnderTest() globalSettings.putString(DEVELOPMENT_SHADE_DISPLAY_AWARENESS, "any_external_display") - assertThat(policy).isInstanceOf(AnyExternalShadeDisplayPolicy::class.java) + assertThat(underTest.currentPolicy) + .isInstanceOf(AnyExternalShadeDisplayPolicy::class.java) } @Test fun policy_updatesBasedOnSettingValue_focusBased() = testScope.runTest { - val policy by collectLastValue(underTest.policy) - + val underTest = createUnderTest() globalSettings.putString(DEVELOPMENT_SHADE_DISPLAY_AWARENESS, "status_bar_latest_touch") - assertThat(policy).isInstanceOf(StatusBarTouchShadeDisplayPolicy::class.java) + assertThat(underTest.currentPolicy) + .isInstanceOf(StatusBarTouchShadeDisplayPolicy::class.java) + } + + @Test + fun displayId_afterKeyguardHides_goesBackToPreviousDisplay() = + testScope.runTest { + val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true) + globalSettings.putString( + DEVELOPMENT_SHADE_DISPLAY_AWARENESS, + FakeShadeDisplayPolicy.name, + ) + + val displayId by collectLastValue(underTest.displayId) + + displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) + FakeShadeDisplayPolicy.setDisplayId(2) + + assertThat(displayId).isEqualTo(2) + + keyguardRepository.setKeyguardShowing(true) + + assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY) + + keyguardRepository.setKeyguardShowing(false) + + assertThat(displayId).isEqualTo(2) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt index eeb3e6b31c69..fd6bc98b006c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt @@ -25,7 +25,7 @@ import com.android.systemui.display.data.repository.displayRepository import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.shade.ShadePrimaryDisplayCommand -import com.android.systemui.shade.display.ShadeDisplayPolicy +import com.android.systemui.shade.display.FakeShadeDisplayPolicy import com.android.systemui.statusbar.commandline.commandRegistry import com.android.systemui.testKosmos import com.android.systemui.util.settings.fakeGlobalSettings @@ -33,8 +33,6 @@ import com.google.common.truth.StringSubject import com.google.common.truth.Truth.assertThat import java.io.PrintWriter import java.io.StringWriter -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -118,23 +116,12 @@ class ShadePrimaryDisplayCommandTest : SysuiTestCase() { @Test fun policies_setsNewPolicy() = testScope.runTest { - val policy by collectLastValue(shadeDisplaysRepository.policy) - val newPolicy = policies.last().name + val newPolicy = FakeShadeDisplayPolicy.name commandRegistry.onShellCommand(pw, arrayOf("shade_display_override", newPolicy)) - assertThat(policy!!.name).isEqualTo(newPolicy) + assertThat(shadeDisplaysRepository.currentPolicy.name).isEqualTo(newPolicy) } - - private fun makePolicy(policyName: String): ShadeDisplayPolicy { - return object : ShadeDisplayPolicy { - override val name: String - get() = policyName - - override val displayId: StateFlow<Int> - get() = MutableStateFlow(0) - } - } } private fun StringSubject.containsAllIn(strings: List<String>) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/FocusShadeDisplayPolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/FocusShadeDisplayPolicyTest.kt new file mode 100644 index 000000000000..b4249ef72e62 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/FocusShadeDisplayPolicyTest.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade.display + +import android.view.Display +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.shade.data.repository.fakeFocusedDisplayRepository +import com.android.systemui.shade.data.repository.focusShadeDisplayPolicy +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test +import kotlinx.coroutines.test.runTest +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class FocusShadeDisplayPolicyTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val testScope = kosmos.testScope + private val focusedDisplayRepository = kosmos.fakeFocusedDisplayRepository + + private val underTest = kosmos.focusShadeDisplayPolicy + + @Test + fun displayId_propagatedFromRepository() = + testScope.runTest { + val displayId by collectLastValue(underTest.displayId) + + assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY) + + focusedDisplayRepository.setDisplayId(2) + + assertThat(displayId).isEqualTo(2) + + focusedDisplayRepository.setDisplayId(3) + + assertThat(displayId).isEqualTo(3) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt index 20dfd3e11947..e43c46b36a06 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt @@ -26,12 +26,11 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.display.data.repository.display import com.android.systemui.display.data.repository.displayRepository -import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.shade.data.repository.statusBarTouchShadeDisplayPolicy import com.android.systemui.shade.domain.interactor.notificationElement import com.android.systemui.shade.domain.interactor.qsElement -import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlin.test.Test @@ -45,22 +44,9 @@ import org.mockito.kotlin.mock class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val testScope = kosmos.testScope - private val keyguardRepository = kosmos.fakeKeyguardRepository private val displayRepository = kosmos.displayRepository - private fun createUnderTest( - shadeOnDefaultDisplayWhenLocked: Boolean = false - ): StatusBarTouchShadeDisplayPolicy { - return StatusBarTouchShadeDisplayPolicy( - displayRepository, - keyguardRepository, - testScope.backgroundScope, - shadeOnDefaultDisplayWhenLocked = shadeOnDefaultDisplayWhenLocked, - shadeInteractor = { kosmos.shadeInteractor }, - { kosmos.qsElement }, - { kosmos.notificationElement }, - ) - } + private val underTest = kosmos.statusBarTouchShadeDisplayPolicy private fun createMotionEventForDisplay(displayId: Int, xCoordinate: Float = 0f): MotionEvent { return mock<MotionEvent> { @@ -71,15 +57,12 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { @Test fun displayId_defaultToDefaultDisplay() { - val underTest = createUnderTest() - assertThat(underTest.displayId.value).isEqualTo(Display.DEFAULT_DISPLAY) } @Test fun onStatusBarTouched_called_updatesDisplayId() = testScope.runTest { - val underTest = createUnderTest() val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) @@ -91,7 +74,6 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { @Test fun onStatusBarTouched_notExistentDisplay_displayIdNotUpdated() = testScope.runTest { - val underTest = createUnderTest() val displayIds by collectValues(underTest.displayId) assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY)) @@ -104,7 +86,6 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { @Test fun onStatusBarTouched_afterDisplayRemoved_goesBackToDefaultDisplay() = testScope.runTest { - val underTest = createUnderTest() val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) @@ -118,46 +99,8 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { } @Test - fun onStatusBarTouched_afterKeyguardVisible_goesBackToDefaultDisplay() = - testScope.runTest { - val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true) - val displayId by collectLastValue(underTest.displayId) - - displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) - underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) - - assertThat(displayId).isEqualTo(2) - - keyguardRepository.setKeyguardShowing(true) - - assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY) - } - - @Test - fun onStatusBarTouched_afterKeyguardHides_goesBackToPreviousDisplay() = - testScope.runTest { - val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true) - val displayId by collectLastValue(underTest.displayId) - - displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) - underTest.onStatusBarTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH) - - assertThat(displayId).isEqualTo(2) - - keyguardRepository.setKeyguardShowing(true) - - assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY) - - keyguardRepository.setKeyguardShowing(false) - - assertThat(displayId).isEqualTo(2) - } - - @Test fun onStatusBarTouched_leftSide_intentSetToNotifications() = testScope.runTest { - val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true) - underTest.onStatusBarTouched( createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.1f), STATUS_BAR_WIDTH, @@ -169,8 +112,6 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { @Test fun onStatusBarTouched_rightSide_intentSetToQs() = testScope.runTest { - val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true) - underTest.onStatusBarTouched( createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.95f), STATUS_BAR_WIDTH, @@ -182,8 +123,6 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { @Test fun onStatusBarTouched_nullAfterConsumed() = testScope.runTest { - val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true) - underTest.onStatusBarTouched( createMotionEventForDisplay(2, STATUS_BAR_WIDTH * 0.1f), STATUS_BAR_WIDTH, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt index d3ba3dceb4cf..246283c236fe 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt @@ -22,17 +22,24 @@ import android.view.Display import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.configurationRepository +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.scene.ui.view.mockShadeRootView import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository +import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository +import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs +import com.android.systemui.statusbar.notification.row.notificationRebindingTracker +import com.android.systemui.statusbar.notification.stack.notificationStackRebindingHider import com.android.systemui.testKosmos -import kotlinx.coroutines.test.advanceUntilIdle +import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.never +import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.kotlin.any import org.mockito.kotlin.eq @@ -42,7 +49,7 @@ import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) @SmallTest class ShadeDisplaysInteractorTest : SysuiTestCase() { - val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val testScope = kosmos.testScope private val shadeRootview = kosmos.mockShadeRootView @@ -52,6 +59,10 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() { private val latencyTracker = kosmos.mockedShadeDisplayChangeLatencyTracker private val configuration = mock<Configuration>() private val display = mock<Display>() + private val activeNotificationRepository = kosmos.activeNotificationListRepository + private val notificationRebindingTracker = kosmos.notificationRebindingTracker + private val notificationStackRebindingHider = kosmos.notificationStackRebindingHider + private val configurationRepository = kosmos.fakeConfigurationRepository private val underTest by lazy { kosmos.shadeDisplaysInteractor } @@ -68,24 +79,26 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() { } @Test - fun start_shadeInCorrectPosition_notAddedOrRemoved() { - whenever(display.displayId).thenReturn(0) - positionRepository.setDisplayId(0) + fun start_shadeInCorrectPosition_notAddedOrRemoved() = + testScope.runTest { + whenever(display.displayId).thenReturn(0) + positionRepository.setDisplayId(0) - underTest.start() + underTest.start() - verify(shadeContext, never()).reparentToDisplay(any()) - } + verify(shadeContext, never()).reparentToDisplay(any()) + } @Test - fun start_shadeInWrongPosition_changes() { - whenever(display.displayId).thenReturn(0) - positionRepository.setDisplayId(1) + fun start_shadeInWrongPosition_changes() = + testScope.runTest { + whenever(display.displayId).thenReturn(0) + positionRepository.setDisplayId(1) - underTest.start() + underTest.start() - verify(shadeContext).reparentToDisplay(eq(1)) - } + verify(shadeContext).reparentToDisplay(eq(1)) + } @Test fun start_shadeInWrongPosition_logsStartToLatencyTracker() = @@ -94,8 +107,81 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() { positionRepository.setDisplayId(1) underTest.start() - advanceUntilIdle() verify(latencyTracker).onShadeDisplayChanging(eq(1)) } + + @Test + fun start_shadeInWrongPosition_someNotificationsVisible_hiddenThenShown() = + testScope.runTest { + whenever(display.displayId).thenReturn(0) + positionRepository.setDisplayId(1) + activeNotificationRepository.setActiveNotifs(1) + + underTest.start() + + verify(notificationStackRebindingHider).setVisible(eq(false), eq(false)) + configurationRepository.onMovedToDisplay(1) + verify(notificationStackRebindingHider).setVisible(eq(true), eq(true)) + } + + @Test + fun start_shadeInWrongPosition_someNotificationsVisible_waitsForInflationsBeforeShowingNssl() = + testScope.runTest { + whenever(display.displayId).thenReturn(0) + positionRepository.setDisplayId(1) + activeNotificationRepository.setActiveNotifs(1) + + val endRebinding = notificationRebindingTracker.trackRebinding("test") + + assertThat(notificationRebindingTracker.rebindingInProgressCount.value).isEqualTo(1) + + underTest.start() + + verify(notificationStackRebindingHider).setVisible(eq(false), eq(false)) + configurationRepository.onMovedToDisplay(1) + + // Verify that setVisible(true, true) is NOT called yet, as we + // first need to wait for notification bindings to have happened + verify(notificationStackRebindingHider, never()).setVisible(eq(true), eq(true)) + + endRebinding.onFinished() + + // Now verify that setVisible(true, true) is called + verify(notificationStackRebindingHider, times(1)).setVisible(eq(true), eq(true)) + } + + @Test + fun start_shadeInWrongPosition_noNotifications_nsslNotHidden() = + testScope.runTest { + whenever(display.displayId).thenReturn(0) + positionRepository.setDisplayId(1) + activeNotificationRepository.setActiveNotifs(0) + + underTest.start() + + verify(notificationStackRebindingHider) + .setVisible(visible = eq(true), animated = eq(false)) + verify(notificationStackRebindingHider, never()).setVisible(eq(false), eq(false)) + verify(notificationStackRebindingHider, never()).setVisible(eq(true), eq(true)) + } + + @Test + fun start_shadeInWrongPosition_waitsUntilMovedToDisplayReceived() = + testScope.runTest { + whenever(display.displayId).thenReturn(0) + positionRepository.setDisplayId(1) + activeNotificationRepository.setActiveNotifs(1) + + underTest.start() + + verify(notificationStackRebindingHider).setVisible(eq(false), eq(false)) + // It's not set to visible yet, as we first need to wait for the view to receive the + // display moved callback. + verify(notificationStackRebindingHider, never()).setVisible(eq(true), eq(true)) + + configurationRepository.onMovedToDisplay(1) + + verify(notificationStackRebindingHider).setVisible(eq(true), eq(true)) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt index eb8ea8ba15cf..0da1e7f11582 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt @@ -102,12 +102,12 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test @DisableFlags(DualShade.FLAG_NAME) - fun onSystemIconContainerClicked_locked_collapsesShadeToLockscreen() = + fun onSystemIconChipClicked_locked_collapsesShadeToLockscreen() = testScope.runTest { setDeviceEntered(false) setScene(Scenes.Shade) - underTest.onSystemIconContainerClicked() + underTest.onSystemIconChipClicked() runCurrent() assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Lockscreen) @@ -115,16 +115,16 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test @EnableFlags(DualShade.FLAG_NAME) - fun onSystemIconContainerClicked_lockedOnDualShade_collapsesShadeToLockscreen() = + fun onSystemIconChipClicked_lockedOnQsShade_collapsesShadeToLockscreen() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) setDeviceEntered(false) setScene(Scenes.Lockscreen) - setOverlay(Overlays.NotificationsShade) + setOverlay(Overlays.QuickSettingsShade) assertThat(currentOverlays).isNotEmpty() - underTest.onSystemIconContainerClicked() + underTest.onSystemIconChipClicked() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) @@ -132,13 +132,32 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { } @Test + @EnableFlags(DualShade.FLAG_NAME) + fun onSystemIconChipClicked_lockedOnNotifShade_expandsQsShade() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + setDeviceEntered(false) + setScene(Scenes.Lockscreen) + setOverlay(Overlays.NotificationsShade) + assertThat(currentOverlays).isNotEmpty() + + underTest.onSystemIconChipClicked() + runCurrent() + + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).contains(Overlays.QuickSettingsShade) + assertThat(currentOverlays).doesNotContain(Overlays.NotificationsShade) + } + + @Test @DisableFlags(DualShade.FLAG_NAME) - fun onSystemIconContainerClicked_unlocked_collapsesShadeToGone() = + fun onSystemIconChipClicked_unlocked_collapsesShadeToGone() = testScope.runTest { setDeviceEntered(true) setScene(Scenes.Shade) - underTest.onSystemIconContainerClicked() + underTest.onSystemIconChipClicked() runCurrent() assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Gone) @@ -146,7 +165,81 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test @EnableFlags(DualShade.FLAG_NAME) - fun onSystemIconContainerClicked_unlockedOnDualShade_collapsesShadeToGone() = + fun onSystemIconChipClicked_unlockedOnQsShade_collapsesShadeToGone() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + setDeviceEntered(true) + setScene(Scenes.Gone) + setOverlay(Overlays.QuickSettingsShade) + assertThat(currentOverlays).isNotEmpty() + + underTest.onSystemIconChipClicked() + runCurrent() + + assertThat(currentScene).isEqualTo(Scenes.Gone) + assertThat(currentOverlays).isEmpty() + } + + @Test + @EnableFlags(DualShade.FLAG_NAME) + fun onSystemIconChipClicked_unlockedOnNotifShade_expandsQsShade() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + setDeviceEntered(true) + setScene(Scenes.Gone) + setOverlay(Overlays.NotificationsShade) + assertThat(currentOverlays).isNotEmpty() + + underTest.onSystemIconChipClicked() + runCurrent() + + assertThat(currentScene).isEqualTo(Scenes.Gone) + assertThat(currentOverlays).contains(Overlays.QuickSettingsShade) + assertThat(currentOverlays).doesNotContain(Overlays.NotificationsShade) + } + + @Test + @EnableFlags(DualShade.FLAG_NAME) + fun onNotificationIconChipClicked_lockedOnNotifShade_collapsesShadeToLockscreen() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + setDeviceEntered(false) + setScene(Scenes.Lockscreen) + setOverlay(Overlays.NotificationsShade) + assertThat(currentOverlays).isNotEmpty() + + underTest.onNotificationIconChipClicked() + runCurrent() + + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).isEmpty() + } + + @Test + @EnableFlags(DualShade.FLAG_NAME) + fun onNotificationIconChipClicked_lockedOnQsShade_expandsNotifShade() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + setDeviceEntered(false) + setScene(Scenes.Lockscreen) + setOverlay(Overlays.QuickSettingsShade) + assertThat(currentOverlays).isNotEmpty() + + underTest.onNotificationIconChipClicked() + runCurrent() + + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).contains(Overlays.NotificationsShade) + assertThat(currentOverlays).doesNotContain(Overlays.QuickSettingsShade) + } + + @Test + @EnableFlags(DualShade.FLAG_NAME) + fun onNotificationIconChipClicked_unlockedOnNotifShade_collapsesShadeToGone() = testScope.runTest { val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) @@ -155,13 +248,32 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { setOverlay(Overlays.NotificationsShade) assertThat(currentOverlays).isNotEmpty() - underTest.onSystemIconContainerClicked() + underTest.onNotificationIconChipClicked() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Gone) assertThat(currentOverlays).isEmpty() } + @Test + @EnableFlags(DualShade.FLAG_NAME) + fun onNotificationIconChipClicked_unlockedOnQsShade_expandsNotifShade() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + setDeviceEntered(true) + setScene(Scenes.Gone) + setOverlay(Overlays.QuickSettingsShade) + assertThat(currentOverlays).isNotEmpty() + + underTest.onNotificationIconChipClicked() + runCurrent() + + assertThat(currentScene).isEqualTo(Scenes.Gone) + assertThat(currentOverlays).contains(Overlays.NotificationsShade) + assertThat(currentOverlays).doesNotContain(Overlays.QuickSettingsShade) + } + companion object { private val SUB_1 = SubscriptionModel( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java index deaf57999b21..0713a247a4a3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -225,6 +225,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { Notification notifWithPrivateVisibility = new Notification(); notifWithPrivateVisibility.visibility = VISIBILITY_PRIVATE; + notifWithPrivateVisibility.when = System.currentTimeMillis(); mCurrentUserNotif = new NotificationEntryBuilder() .setNotification(notifWithPrivateVisibility) .setUser(new UserHandle(mCurrentUser.id)) @@ -260,7 +261,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { .setChannel(channel) .setSensitiveContent(true) .setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build()); - mSensitiveNotifPostTime = mSensitiveContentNotif.getSbn().getPostTime(); + mSensitiveNotifPostTime = mSensitiveContentNotif.getSbn().getNotification().getWhen(); when(mNotifCollection.getEntry(mWorkProfileNotif.getKey())).thenReturn(mWorkProfileNotif); when(mKeyguardInteractorLazy.get()).thenReturn(mKeyguardInteractor); when(mKeyguardInteractor.isKeyguardDismissible()) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/compose/ChronometerStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChronometerStateTest.kt index e68045fe470f..4e92540396d3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/compose/ChronometerStateTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChronometerStateTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 The Android Open Source Project + * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.chips.ui.compose +package com.android.systemui.statusbar.chips.ui.viewmodel import android.text.format.DateUtils.formatElapsedTime import androidx.test.ext.junit.runners.AndroidJUnit4 diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt index 8bca17f72c9f..25ae13fefdd7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt @@ -109,6 +109,7 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() { private val statusBarService: IStatusBarService = mock() private val uiEventLogger: UiEventLogger = mock() private val msdlPlayer: MSDLPlayer = mock() + private val rebindingTracker: NotificationRebindingTracker = mock() private lateinit var controller: ExpandableNotificationRowController @Before @@ -150,6 +151,7 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() { statusBarService, uiEventLogger, msdlPlayer, + rebindingTracker, ) whenever(view.childrenContainer).thenReturn(childrenContainer) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRebindingTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRebindingTrackerTest.kt new file mode 100644 index 000000000000..8bffab617e0a --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRebindingTrackerTest.kt @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.row + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository +import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class NotificationRebindingTrackerTest : SysuiTestCase() { + + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val testScope = kosmos.testScope + private val activeNotificationRepository = kosmos.activeNotificationListRepository + + private val underTest: NotificationRebindingTracker = kosmos.notificationRebindingTracker + + @Before + fun setup() { + underTest.start() + } + + @Test + fun rebindingInProgressCount_noneStarted_isZero() = + testScope.runTest { + val count by collectLastValue(underTest.rebindingInProgressCount) + + assertThat(count).isEqualTo(0) + } + + @Test + fun rebindingInProgressCount_oneStarted_isOne() = + testScope.runTest { + val count by collectLastValue(underTest.rebindingInProgressCount) + activeNotificationRepository.setActiveNotifs(1) + + underTest.trackRebinding("0") + + assertThat(count).isEqualTo(1) + } + + @Test + fun rebindingInProgressCount_oneStartedThenFinished_goesFromOneToZero() = + testScope.runTest { + val count by collectLastValue(underTest.rebindingInProgressCount) + activeNotificationRepository.setActiveNotifs(1) + + val endRebinding = underTest.trackRebinding("0") + + assertThat(count).isEqualTo(1) + + endRebinding.onFinished() + + assertThat(count).isEqualTo(0) + } + + @Test + fun rebindingInProgressCount_twoStarted_goesToTwo() = + testScope.runTest { + val count by collectLastValue(underTest.rebindingInProgressCount) + activeNotificationRepository.setActiveNotifs(2) + + underTest.trackRebinding("0") + underTest.trackRebinding("1") + + assertThat(count).isEqualTo(2) + } + + @Test + fun rebindingInProgressCount_twoStarted_oneNotActiveAnymore_goesToZero() = + testScope.runTest { + val count by collectLastValue(underTest.rebindingInProgressCount) + activeNotificationRepository.setActiveNotifs(2) + + val finishFirstRebinding = underTest.trackRebinding("0") + underTest.trackRebinding("1") + + assertThat(count).isEqualTo(2) + + activeNotificationRepository.setActiveNotifs(1) + + assertThat(count).isEqualTo(1) + + finishFirstRebinding.onFinished() + + assertThat(count).isEqualTo(0) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index b8d18757afbb..c39b252cd795 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -653,7 +653,8 @@ public class NotificationTestHelper { mock(SmartReplyConstants.class), mock(SmartReplyController.class), mock(IStatusBarService.class), - mock(UiEventLogger.class)); + mock(UiEventLogger.class), + mock(NotificationRebindingTracker.class)); row.setAboveShelfChangedListener(aboveShelf -> { }); mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt new file mode 100644 index 000000000000..d0cc56860ce8 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2025 The Android Open 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.volume.panel.component.mediaoutput.domain + +import android.content.mockedContext +import android.content.packageManager +import android.content.pm.PackageManager.FEATURE_PC +import android.testing.TestableLooper +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +class MediaOutputAvailabilityCriteriaTest : SysuiTestCase() { + + private val kosmos = testKosmos() + private val scope = kosmos.testScope + + private lateinit var underTest: MediaOutputAvailabilityCriteria + + @Before + fun setup() { + with(kosmos) { + underTest = MediaOutputAvailabilityCriteria(kosmos.mockedContext, scope.backgroundScope) + } + } + + @Test + fun isDesktop_unavailable() = + kosmos.runTest { + whenever(mockedContext.getPackageManager()).thenReturn(packageManager) + whenever(packageManager.hasSystemFeature(FEATURE_PC)).thenReturn(true) + + val isAvailable by collectLastValue(underTest.isAvailable()) + + assertThat(isAvailable).isFalse() + } + + @Test + fun notIsDesktop_available() = + kosmos.runTest { + whenever(mockedContext.getPackageManager()).thenReturn(packageManager) + whenever(packageManager.hasSystemFeature(FEATURE_PC)).thenReturn(false) + + val isAvailable by collectLastValue(underTest.isAvailable()) + + assertThat(isAvailable).isTrue() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt index 111c232280c3..2985053f56d5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt @@ -19,10 +19,11 @@ package com.android.systemui.wallpapers.data.repository import android.app.WallpaperInfo import android.view.View import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf /** Fake implementation of the wallpaper repository. */ class FakeWallpaperRepository : WallpaperRepository { override val wallpaperInfo = MutableStateFlow<WallpaperInfo?>(null) - override val wallpaperSupportsAmbientMode = MutableStateFlow(false) + override val wallpaperSupportsAmbientMode = flowOf(false) override var rootView: View? = null } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt index b8dd334dcad9..03753d9aa884 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt @@ -24,11 +24,13 @@ import android.content.pm.UserInfo import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.internal.R import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeKeyguardClockRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.shared.Flags as SharedFlags import com.android.systemui.user.data.model.SelectedUserModel import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.FakeUserRepository @@ -74,10 +76,6 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { @Before fun setUp() { whenever(wallpaperManager.isWallpaperSupported).thenReturn(true) - context.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_dozeSupportsAodWallpaper, - true, - ) } @Test @@ -225,214 +223,29 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { } @Test - fun wallpaperInfo_deviceDoesNotSupportAmbientWallpaper_alwaysFalse() = + @EnableFlags(SharedFlags.FLAG_AMBIENT_AOD) + fun wallpaperSupportsAmbientMode_deviceDoesNotSupport_false() = testScope.runTest { context.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_dozeSupportsAodWallpaper, + R.bool.config_dozeSupportsAodWallpaper, false, ) - val latest by collectLastValue(underTest.wallpaperInfo) - assertThat(latest).isNull() - - // Even WHEN there *is* current wallpaper - val wp1 = mock<WallpaperInfo>() - whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(wp1) - fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( - context, - Intent(Intent.ACTION_WALLPAPER_CHANGED), - ) - - // THEN the value is still null because wallpaper isn't supported - assertThat(latest).isNull() - } - - @Test - fun wallpaperSupportsAmbientMode_nullInfo_false() = - testScope.runTest { - val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) - - whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(null) - - fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( - context, - Intent(Intent.ACTION_WALLPAPER_CHANGED), - ) - - assertThat(latest).isFalse() - } - - @Test - fun wallpaperSupportsAmbientMode_infoDoesNotSupport_false() = - testScope.runTest { - val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) - - whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(UNSUPPORTED_WP) - - fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( - context, - Intent(Intent.ACTION_WALLPAPER_CHANGED), - ) - - assertThat(latest).isFalse() - } - - @Test - fun wallpaperSupportsAmbientMode_infoSupports_true() = - testScope.runTest { - val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) - - whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(SUPPORTED_WP) - - fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( - context, - Intent(Intent.ACTION_WALLPAPER_CHANGED), - ) - - assertThat(latest).isTrue() - } - - @Test - fun wallpaperSupportsAmbientMode_initialValueIsFetched_true() = - testScope.runTest { - whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_SUPPORTED_WP.id)) - .thenReturn(SUPPORTED_WP) - userRepository.setUserInfos(listOf(USER_WITH_SUPPORTED_WP)) - userRepository.setSelectedUserInfo(USER_WITH_SUPPORTED_WP) - - // Start up the repo and let it run the initial fetch - underTest.wallpaperSupportsAmbientMode - runCurrent() - - // WHEN the repo initially starts up (underTest is lazy), then it fetches the current - // value for the wallpaper - assertThat(underTest.wallpaperSupportsAmbientMode.value).isTrue() - } - - @Test - fun wallpaperSupportsAmbientMode_initialValueIsFetched_false() = - testScope.runTest { - whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_UNSUPPORTED_WP.id)) - .thenReturn(UNSUPPORTED_WP) - userRepository.setUserInfos(listOf(USER_WITH_UNSUPPORTED_WP)) - userRepository.setSelectedUserInfo(USER_WITH_UNSUPPORTED_WP) - - // WHEN the repo initially starts up (underTest is lazy), then it fetches the current - // value for the wallpaper - assertThat(underTest.wallpaperSupportsAmbientMode.value).isFalse() - } - - @Test - fun wallpaperSupportsAmbientMode_updatesOnUserChanged() = - testScope.runTest { - val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) - - whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_SUPPORTED_WP.id)) - .thenReturn(SUPPORTED_WP) - whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_UNSUPPORTED_WP.id)) - .thenReturn(UNSUPPORTED_WP) - userRepository.setUserInfos(listOf(USER_WITH_SUPPORTED_WP, USER_WITH_UNSUPPORTED_WP)) - - // WHEN a user with supported wallpaper is selected - userRepository.setSelectedUserInfo(USER_WITH_SUPPORTED_WP) - - // THEN it's true - assertThat(latest).isTrue() - - // WHEN the user is switched to a user with unsupported wallpaper - userRepository.setSelectedUserInfo(USER_WITH_UNSUPPORTED_WP) - - // THEN it's false - assertThat(latest).isFalse() - } - - @Test - fun wallpaperSupportsAmbientMode_doesNotUpdateOnUserChanging() = - testScope.runTest { - val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) - - whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_SUPPORTED_WP.id)) - .thenReturn(SUPPORTED_WP) - whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_UNSUPPORTED_WP.id)) - .thenReturn(UNSUPPORTED_WP) - userRepository.setUserInfos(listOf(USER_WITH_SUPPORTED_WP, USER_WITH_UNSUPPORTED_WP)) - - // WHEN a user with supported wallpaper is selected - userRepository.setSelectedUserInfo(USER_WITH_SUPPORTED_WP) - - // THEN it's true - assertThat(latest).isTrue() - - // WHEN the user has started switching to a user with unsupported wallpaper but hasn't - // finished yet - userRepository.selectedUser.value = - SelectedUserModel(USER_WITH_UNSUPPORTED_WP, SelectionStatus.SELECTION_IN_PROGRESS) - - // THEN it still matches the old user - assertThat(latest).isTrue() - } - - @Test - fun wallpaperSupportsAmbientMode_updatesOnIntent() = - testScope.runTest { - val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) - - whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(UNSUPPORTED_WP) - - assertThat(latest).isFalse() - - // WHEN the info now supports ambient mode and a broadcast is sent - whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(SUPPORTED_WP) - fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( - context, - Intent(Intent.ACTION_WALLPAPER_CHANGED), - ) - - // THEN the flow updates - assertThat(latest).isTrue() - } - - @Test - fun wallpaperSupportsAmbientMode_wallpaperNotSupported_alwaysFalse() = - testScope.runTest { - whenever(wallpaperManager.isWallpaperSupported).thenReturn(false) - val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) assertThat(latest).isFalse() - - // Even WHEN the current wallpaper *does* support ambient mode - whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(SUPPORTED_WP) - - fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( - context, - Intent(Intent.ACTION_WALLPAPER_CHANGED), - ) - - // THEN the value is still false because wallpaper isn't supported - assertThat(latest).isFalse() } @Test - fun wallpaperSupportsAmbientMode_deviceDoesNotSupportAmbientWallpaper_alwaysFalse() = + @EnableFlags(SharedFlags.FLAG_AMBIENT_AOD) + fun wallpaperSupportsAmbientMode_deviceDoesSupport_true() = testScope.runTest { context.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_dozeSupportsAodWallpaper, - false, + R.bool.config_dozeSupportsAodWallpaper, + true, ) val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) - assertThat(latest).isFalse() - - // Even WHEN the current wallpaper *does* support ambient mode - whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(SUPPORTED_WP) - - fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( - context, - Intent(Intent.ACTION_WALLPAPER_CHANGED), - ) - - // THEN the value is still false because the device doesn't support it - assertThat(latest).isFalse() + assertThat(latest).isTrue() } @Test diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceLayout.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceLayout.kt index a075d0d5b249..37b611f3c6b9 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceLayout.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockFaceLayout.kt @@ -111,28 +111,37 @@ class DefaultClockFaceLayout(val view: View) : ClockFaceLayout { connect(lockscreenClockViewLargeId, START, PARENT_ID, START) connect(lockscreenClockViewLargeId, END, PARENT_ID, END) - // In preview, we'll show UDFPS icon for UDFPS devices - // and nothing for non-UDFPS devices, - // and we're not planning to add this vide in clockHostView - // so we only need position of device entry icon to constrain clock - // Copied calculation codes from applyConstraints in DefaultDeviceEntrySection - clockPreviewConfig.lockId?.let { lockId -> - connect(lockscreenClockViewLargeId, BOTTOM, lockId, TOP) + clockPreviewConfig.udfpsTop?.let { + val screenHeight = context.resources.displayMetrics.heightPixels + connect( + lockscreenClockViewLargeId, + BOTTOM, + PARENT_ID, + BOTTOM, + (screenHeight - it).toInt(), + ) } ?: run { - val bottomPaddingPx = context.getDimen("lock_icon_margin_bottom") - val defaultDensity = - DisplayMetrics.DENSITY_DEVICE_STABLE.toFloat() / - DisplayMetrics.DENSITY_DEFAULT.toFloat() - val lockIconRadiusPx = (defaultDensity * 36).toInt() - val clockBottomMargin = bottomPaddingPx + 2 * lockIconRadiusPx - connect( - lockscreenClockViewLargeId, - BOTTOM, - PARENT_ID, - BOTTOM, - clockBottomMargin, - ) + // Copied calculation codes from applyConstraints in + // DefaultDeviceEntrySection + clockPreviewConfig.lockId?.let { lockId -> + connect(lockscreenClockViewLargeId, BOTTOM, lockId, TOP) + } + ?: run { + val bottomPaddingPx = context.getDimen("lock_icon_margin_bottom") + val defaultDensity = + DisplayMetrics.DENSITY_DEVICE_STABLE.toFloat() / + DisplayMetrics.DENSITY_DEFAULT.toFloat() + val lockIconRadiusPx = (defaultDensity * 36).toInt() + val clockBottomMargin = bottomPaddingPx + 2 * lockIconRadiusPx + connect( + lockscreenClockViewLargeId, + BOTTOM, + PARENT_ID, + BOTTOM, + clockBottomMargin, + ) + } } val smallClockViewId = context.getId("lockscreen_clock_view") diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPreviewConfig.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPreviewConfig.kt index c705c51a00d5..abc8e150bfd2 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPreviewConfig.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockPreviewConfig.kt @@ -25,6 +25,7 @@ data class ClockPreviewConfig( val isShadeLayoutWide: Boolean, val isSceneContainerFlagEnabled: Boolean = false, val lockId: Int? = null, + val udfpsTop: Float? = null, ) { fun getSmallClockTopPadding( statusBarHeight: Int = SystemBarUtils.getStatusBarHeight(context) diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index b256518e99ac..433c0a71008d 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -128,7 +128,7 @@ <item name="android:windowNoTitle">true</item> <item name="android:windowFullscreen">true</item> <item name="android:windowContentOverlay">@null</item> - <item name="android:colorBackground">@*android:color/background_material_dark</item> + <item name="android:colorBackground">@android:color/transparent</item> </style> <style name="TextAppearance.Keyguard"> diff --git a/packages/SystemUI/res/drawable-nodpi/hub_onboarding_bg.png b/packages/SystemUI/res/drawable-nodpi/hub_onboarding_bg.png Binary files differnew file mode 100644 index 000000000000..bd55e83b377b --- /dev/null +++ b/packages/SystemUI/res/drawable-nodpi/hub_onboarding_bg.png diff --git a/packages/SystemUI/res/drawable/ic_widgets.xml b/packages/SystemUI/res/drawable/ic_widgets.xml deleted file mode 100644 index 9e05809bfb33..000000000000 --- a/packages/SystemUI/res/drawable/ic_widgets.xml +++ /dev/null @@ -1,26 +0,0 @@ -<!-- - ~ Copyright (C) 2024 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:tint="?attr/colorControlNormal" - android:viewportHeight="960" - android:viewportWidth="960"> - <path - android:fillColor="@android:color/black" - android:pathData="M666,520L440,294L666,68L892,294L666,520ZM120,440L120,120L440,120L440,440L120,440ZM520,840L520,520L840,520L840,840L520,840ZM120,840L120,520L440,520L440,840L120,840ZM200,360L360,360L360,200L200,200L200,360ZM667,408L780,295L667,182L554,295L667,408ZM600,760L760,760L760,600L600,600L600,760ZM200,760L360,760L360,600L200,600L200,760ZM360,360L360,360L360,360L360,360L360,360ZM554,295L554,295L554,295L554,295L554,295ZM360,600L360,600L360,600L360,600L360,600ZM600,600L600,600L600,600L600,600L600,600Z" /> -</vector> diff --git a/packages/SystemUI/res/layout/media_projection_recent_tasks.xml b/packages/SystemUI/res/layout/media_projection_recent_tasks.xml index 31baf26e4a1b..3c810a43a3a7 100644 --- a/packages/SystemUI/res/layout/media_projection_recent_tasks.xml +++ b/packages/SystemUI/res/layout/media_projection_recent_tasks.xml @@ -51,5 +51,5 @@ android:layout_marginTop="24dp" android:importantForAccessibility="no" android:src="@*android:drawable/ic_drag_handle" - android:tint="?android:attr/textColorSecondary" /> + android:tint="@*android:color/materialColorSecondary" /> </LinearLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 5e7d9c4a041b..91d92a21ddf1 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Dateer tans op"</string> <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Jy sal nie jou volgende wekker <xliff:g id="WHEN">%1$s</xliff:g> hoor nie"</string> <string name="alarm_template" msgid="2234991538018805736">"om <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"op <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliet, goeie toestand"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliet, verbinding is beskikbaar"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelliet-SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Net noodoproepe of SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"geen sein nie"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"een staaf"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Terug"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Kennisgewings"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Kortpadsleutels"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Wissel sleutelborduitleg"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"of"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Maak soeknavraag skoon"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Kortpadsleutels"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Stelselapps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Verrigting van veelvuldige take"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Verdeelde skerm"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Invoer"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Appkortpaaie"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Huidige app"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Pasmaak kortpaaie"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Verwyder kortpad?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Stel terug na verstek?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Druk sleutel om kortpad toe te wys"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Druk die handelingsleutel en een of meer ander sleutels saam om hierdie kortpad te skep"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Dit sal jou gepasmaakte kortpad permanent uitvee."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Dit sal al jou gepasmaakte kortpaaie permanent uitvee."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Soekkortpaaie"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ja, stel terug"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Kanselleer"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Druk sleutel"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Sleutelkombinasie is reeds in gebruik. Probeer ’n ander sleutel."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Sleutelkombinasie is reeds in gebruik. Probeer ’n ander kombinasie."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Kortpad kan nie gestel word nie."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Voeg kortpad by"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Gaan terug"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Gaan na tuisskerm"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Bekyk onlangse apps"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Wissel apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klaar"</string> <string name="gesture_error_title" msgid="469064941635578511">"Probeer weer!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gaan terug"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Knap gedaan!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Jy het die Bekyk Onlangse Apps-gebaar voltooi."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Swiep op en hou met drie vingers op jou raakpaneel om onlangse apps te bekyk"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Wissel apps"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Uitstekende werk!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Jy het die “wissel tussen apps”-gebaar voltooi."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Bekyk alle apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Druk die handelingsleutel op jou sleutelbord"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Welgedaan!"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index d969525b7c4a..6e079a2a647f 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"በማዘመን ላይ"</string> <string name="status_bar_work" msgid="5238641949837091056">"የስራ መገለጫ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"የአውሮፕላን ሁነታ"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"የእርስዎን ቀጣይ ማንቂያ <xliff:g id="WHEN">%1$s</xliff:g> አይሰሙም"</string> <string name="alarm_template" msgid="2234991538018805736">"በ<xliff:g id="WHEN">%1$s</xliff:g> ላይ"</string> <string name="alarm_template_far" msgid="3561752195856839456">"በ<xliff:g id="WHEN">%1$s</xliff:g> ላይ"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ሳተላይት፣ ጥሩ ግንኙነት"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ሳተላይት፣ ግንኙነት አለ"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ሳተላይት ኤስኦኤስ"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"የአደጋ ጥሪዎች ወይም ኤስኦኤስ ብቻ"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>፣ <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>።"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ምንም ምልክት የለም"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"አንድ አሞሌ"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"ተመለስ"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"ማሳወቂያዎች"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"የቁልፍ ሰሌዳ አቋራጮች"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"የቁልፍ ሰሌዳ ገጽታ ለውጥ"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ወይም"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"የፍለጋ መጠይቅን አጽዳ"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"የቁልፍ ሰሌዳ አቋራጮች"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"የሥርዓት መተግበሪያዎች"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ብዙ ተግባራትን በተመሳሳይ ጊዜ ማከናወን"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"የተከፈለ ማያ ገፅ"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ግብዓት"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"የመተግበሪያ አቋራጮች"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"የአሁን መተግበሪያ"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"አቋራጮችን ያብጁ"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"አቋራጭ ይወገድ?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ወደ ነባሪ ዳግም ይጀመር?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"አቋራጭ ለመመደብ ቁልፍ ይጫኑ"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"ይህን አቋራጭ ለመፍጠር የእርምጃ ቁልፉን እና ላይ አንድ ወይም ከዚያ በላይ ሌሎቹ ቁልፎችን አንድ ላይ ይጫኑ"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ይህ ብጁ አቋራጭዎን በቋሚነት ይሰርዛል።"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ይህ ሁሉንም ብጁ አቋራጮችዎን በቋሚነት ይሰርዛል።"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"የፍለጋ አቋራጮች"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"አዎ፣ ዳግም አስጀምር"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ይቅር"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ቁልፍ ይጫኑ"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"የቁልፍ ጥምረት አስቀድሞ በሥራ ላይ ነው። ሌላ ቁልፍ ይሞክሩ።"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"የቁልፍ ጥምረት ቀድሞውኑ ጥቅም ላይ ውሏል። ሌላ ጥምረት ይሞክሩ።"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"አቋራጩ ሊቀናበር አይችልም።"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"አቋራጭ አክል"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ወደኋላ ተመለስ"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ወደ መነሻ ሂድ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"የቅርብ ጊዜ መተግበሪያዎችን አሳይ"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"መተግበሪያዎችን ይቀያይሩ"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ተከናውኗል"</string> <string name="gesture_error_title" msgid="469064941635578511">"እንደገና ይሞክሩ!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ወደኋላ ተመለስ"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ጥሩ ሠርተዋል!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"የቅርብ ጊዜ መተግበሪያዎች አሳይ ምልክትን አጠናቅቀዋል።"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"የቅርብ ጊዜ መተግበሪያዎችን ለማየት የመዳሰሻ ሰሌዳዎ ላይ ሦስት ጣቶችን በመጠቀም ወደላይ ያንሸራትቱ እና ይያዙ"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"መተግበሪያዎችን ይቀያይሩ"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ጥሩ ሠርተዋል!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"የመተግበሪያ ምልክቶችን ይቀይሩ የሚለወን አጠናቅቀዋል።"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ሁሉንም መተግበሪያዎች ይመልከቱ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"በቁልፍ ሰሌዳዎ ላይ ያለውን የተግባር ቁልፍ ይጫኑ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ጥሩ ሠርተዋል!"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index d46df1d8b348..7896cdbd68f8 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"جارٍ تعديل الحالة"</string> <string name="status_bar_work" msgid="5238641949837091056">"ملف العمل"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"وضع الطيران"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"لن تسمع المنبّه القادم في <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"في <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"يوم <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"قمر صناعي، الاتصال جيد"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"قمر صناعي، الاتصال متوفّر"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"اتصالات الطوارئ بالقمر الصناعي"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"مكالمات الطوارئ أو اتصالات الطوارئ فقط"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"\"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>\"، <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ما مِن أشرطة إشارة"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"شريط إشارة واحد"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"رجوع"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"الإشعارات"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"اختصارات لوحة المفاتيح"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"تبديل تنسيق لوحة المفاتيح"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"أو"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"محو طلب البحث"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"اختصارات لوحة المفاتيح"</string> @@ -1432,16 +1432,17 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"تطبيقات النظام"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"تعدُّد المهام"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"تقسيم الشاشة"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"الإدخال"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"اختصارات التطبيقات"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"التطبيق الحالي"</string> <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"تسهيل الاستخدام"</string> <string name="shortcut_helper_title" msgid="8567500639300970049">"اختصارات لوحة المفاتيح"</string> - <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) --> - <skip /> + <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"تخصيص الاختصارات"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"هل تريد إزالة هذا الاختصار؟"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"يُرجى تأكيد إعادة الضبط على الإعدادات التلقائية"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"اضغط على مفتاح لتخصيص الاختصار"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"لإنشاء هذا الاختصار، يُرجى الضغط على مفتاح الإجراء ومفتاح آخر أو أكثر معًا"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"سيؤدي هذا الإجراء إلى حذف الاختصار المخصّص نهائيًا."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"سيؤدي هذا الإجراء إلى حذف جميع الاختصارات المخصّصة نهائيًا."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"البحث في الاختصارات"</string> @@ -1463,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"نعم، أريد إعادة الضبط"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"إلغاء"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"اضغط على مفتاح"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"يتم حاليًا استخدام مجموعة المفاتيح هذه. يُرجى تجربة مفتاح آخر."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"يتم حاليًا استخدام مجموعة المفاتيح هذه. يُرجى تجربة مجموعة أخرى من المفاتيح."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"تعذَّر ضبط الاختصار."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"إضافة اختصار"</string> @@ -1477,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"رجوع"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"الانتقال إلى الصفحة الرئيسية"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"عرض التطبيقات المستخدَمة مؤخرًا"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"التبديل بين التطبيقات"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"تم"</string> <string name="gesture_error_title" msgid="469064941635578511">"يُرجى إعادة المحاولة"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"رجوع"</string> @@ -1494,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"أحسنت."</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"لقد أكملْت التدريب على إيماءة عرض التطبيقات المستخدَمة مؤخرًا."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"لعرض التطبيقات المستخدَمة مؤخرًا، يُرجى التمرير سريعًا للأعلى مع الاستمرار باستخدام ثلاثة أصابع على لوحة اللمس"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"التبديل بين التطبيقات"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"أحسنت صنعًا."</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"أكملت التدريب على إيماءة التبديل بين التطبيقات."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"عرض جميع التطبيقات"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"اضغط على مفتاح الإجراء في لوحة المفاتيح"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"أحسنت!"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index ff5e2106a8d2..7c99df9a8c78 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"আপডে’ট কৰি থকা হৈছে"</string> <string name="status_bar_work" msgid="5238641949837091056">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"এয়াৰপ্লে’ন ম’ড"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"আপুনি আপোনাৰ পিছৰটো এলাৰ্ম <xliff:g id="WHEN">%1$s</xliff:g> বজাত শুনা নাপাব"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> বজাত"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> বজাত"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"উপগ্ৰহ, ভাল সংযোগ"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"উপগ্ৰহ, সংযোগ উপলব্ধ"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"উপগ্ৰহ SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"কেৱল জৰুৰীকালীন কল বা SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"কোনো ছিগনেল নাই"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"এডাল দণ্ড"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"উভতি যাওক"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"জাননীসমূহ"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"কীব\'ৰ্ড শ্বৰ্টকাটসমূহ"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"কীব\'ৰ্ডৰ সজ্জা সলনি কৰক"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"অথবা"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"সন্ধান কৰা প্ৰশ্ন মচক"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"কীব’ৰ্ডৰ শ্বৰ্টকাট"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"ছিষ্টেম এপ্"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"মাল্টিটাস্কিং"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"বিভাজিত স্ক্ৰীন"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ইনপুট"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"এপ্ শ্বৰ্টকাটসমূহ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"বৰ্তমানৰ এপ্"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"শ্বৰ্টকাট কাষ্টমাইজ কৰক"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"শ্বৰ্টকাট আঁতৰাবনে?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ডিফ\'ল্ট হিচাপে পুনৰ ৰিছেট কৰিবনে?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"শ্বৰ্টকাটৰ ভূমিকা অৰ্পণ কৰিবলৈ কী টিপক"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"এই শ্বৰ্টকাটটো সৃষ্টি কৰিবলৈ, কাৰ্য কী আৰু এক বা একাধিক কী একেলগে টিপক"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"এইটোৱে আপোনাৰ কাষ্টম শ্বৰ্টকাট মচিব।"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"এইটোৱে আপোনাৰ আটাইবোৰ কাষ্টম শ্বৰ্টকাট স্থায়ীভাৱে মচিব।"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"সন্ধানৰ শ্বৰ্টকাট"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"হয়, ৰিছেট কৰক"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"বাতিল কৰক"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"কী টিপক"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"কীৰ মিশ্ৰণ ইতিমধ্যে ব্যৱহাৰ হৈ আছে। অন্য এটা কী ব্যৱহাৰ কৰি চাওক।"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"কীৰ মিশ্ৰণ ইতিমধ্যে ব্যৱহাৰ হৈ আছে। অন্য এটা মিশ্ৰণ ব্যৱহাৰ কৰি চাওক।"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"শ্বৰ্টকাট ছেট কৰিব নোৱাৰি।"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"শ্বৰ্টকাট যোগ দিয়ক"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"উভতি যাওক"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"গৃহ পৃষ্ঠালৈ যাওক"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"শেহতীয়া এপ্সমূহ চাওক"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"এপ্সমূহ সলনি কৰক"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"হ’ল"</string> <string name="gesture_error_title" msgid="469064941635578511">"পুনৰ চেষ্টা কৰক!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"উভতি যাওক"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"বঢ়িয়া!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"আপুনি শেহতীয়া এপ্ চোৱাৰ নিৰ্দেশনাটো সম্পূৰ্ণ কৰিছে।"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"শেহতীয়া এপ্সমূহ চাবলৈ, আপোনাৰ টাচ্চপেডত তিনিটা আঙুলি ব্যৱহাৰ কৰি ওপৰলৈ ছোৱাইপ কৰি ধৰি ৰাখক"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"এপ্সমূহ সলনি কৰক"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"বঢ়িয়া!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"আপুনি এপ্ সলনি কৰাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে।"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"আটাইবোৰ এপ্ চাওক"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"আপোনাৰ কীব’ৰ্ডৰ কাৰ্য কীটোত টিপক"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"বঢ়িয়া!"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index dbeacf0bf277..64b2726f26d8 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Güncəllənir"</string> <string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Təyyarə rejimi"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> zaman növbəti xəbərdarlığınızı eşitməyəcəksiniz"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Peyk, bağlantı yaxşıdır"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Peyk, bağlantı var"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Təcili peyk bağlantısı"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Təcili zəng və ya sadəcə SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"siqnal yoxdur"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"bir zolaq"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Geri"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Bildirişlər"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Klaviatura qısa yolları"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Klaviatura düzümünü dəyişin"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"və ya"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Axtarış sorğusunu silin"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Klaviatura qısayolları"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistem tətbiqləri"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Çoxsaylı tapşırıq icrası"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Bölünmüş ekran"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Daxiletmə"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Tətbiq qısayolları"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Cari tətbiq"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Qısayolları fərdiləşdirin"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Qısayol silinsin?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Defolt vəziyyətə qaytarılsın?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Qısayol təyin etmək üçün düyməni basın"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Bu qısayolu yaratmaq üçün Fəaliyyət düyməsini, habelə bir və ya bir neçə digər düyməni birlikdə basın"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Bu, fərdi qısayolunuzu həmişəlik siləcək."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Bu, bütün fərdi qısayollarınızı həmişəlik siləcək."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Axtarış qısayolları"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Bəli, sıfırlayın"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Ləğv edin"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Düyməni basın"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Düymə kombinasiyası artıq istifadə olunur. Başqa düyməni sınayın."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Düymə kombinasiyası artıq istifadə olunur. Başqa kombinasiyanı sınayın."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Qısayol ayarlana bilməz."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Qısayol əlavə edin"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Geri qayıdın"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Əsas səhifəyə keçin"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Son tətbiqlərə baxın"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Başqa tətbiqə keçin"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hazırdır"</string> <string name="gesture_error_title" msgid="469064941635578511">"Yenidən cəhd edin!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri qayıdın"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Əla!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Son tətbiqlərə baxmaq jestini tamamladınız."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Ən son tətbiqlərə baxmaq üçün taçpeddə üç barmağınızla yuxarı çəkin və saxlayın"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Başqa tətbiqə keçin"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Əla!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Tətbiqlərarası keçid jestini tamamladınız."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Bütün tətbiqlərə baxın"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Klaviaturada fəaliyyət açarına basın"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Əla!"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index ca01a3d89ebe..31566929dae0 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ažurira se"</string> <string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Režim rada u avionu"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sledeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, veza je dobra"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Hitna pomoć preko satelita"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Samo hitni pozivi ili hitna pomoć"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"nema signala"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"jedna crta"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Nazad"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Obaveštenja"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Tasterske prečice"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Promeni raspored tastature"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ili"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Obriši upit za pretragu"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tasterske prečice"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistemske aplikacije"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Obavljanje više zadataka istovremeno"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Podeljeni ekran"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Unos"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Prečice za aplikacije"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuelna aplikacija"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Prilagodite prečice"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Želite da uklonite prečicu?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Želite da resetujete na podrazumevano?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite taster da biste dodelili prečicu"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Da biste napravili ovu prečicu, pritisnite zajedno taster radnji i jedan ili više drugih tastera"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Ovim ćete trajno izbrisati prilagođenu prečicu."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Time ćete trajno izbrisati sve prilagođene prečice."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pretražite prečice"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Da, resetuj"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Otkaži"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite taster"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinacija tastera se već koristi. Probajte sa drugim tasterom."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Kombinacija tastera se već koristi. Probajte sa drugom kombinacijom."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Podešavanje prečice nije uspelo."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Dodajte prečicu"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Nazad"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Idi na početni ekran"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Prikaži nedavno korišćene aplikacije"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Pređi na drugu aplikaciju"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string> <string name="gesture_error_title" msgid="469064941635578511">"Probajte ponovo."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Odlično!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Dovršili ste pokret za prikazivanje nedavno korišćenih aplikacija."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Da biste pregledali nedavne aplikacije, prevucite nagore i zadržite sa tri prsta na tačpedu"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Pređi na drugu aplikaciju"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Odlično!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Dovršili ste pokret za promenu aplikacija."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Prikaži sve aplikacije"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite taster radnji na tastaturi"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 40d78c20859b..5e339a4ea07e 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Абнаўленне…"</string> <string name="status_bar_work" msgid="5238641949837091056">"Працоўны профіль"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Рэжым палёту"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Вы не пачуеце наступны будзільнік <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Спадарожнікавая сувязь, добрае падключэнне"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Спадарожнікавая сувязь, падключэнне даступнае"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Экстраннае спадарожнікавае падключэнне"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Экстранныя выклікі або толькі экстраннае спадарожнікавае падключэнне"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"няма сігналу"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"адзiн слупок"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Назад"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Апавяшчэнні"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Спалучэнні клавіш"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Пераключыць раскладку клавіятуры"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"або"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Ачысціць пошукавы запыт"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Спалучэнні клавіш"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Сістэмныя праграмы"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Шматзадачнасць"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Падзелены экран"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Увод"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Ярлыкі праграм"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Бягучая праграма"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Наладзіць спалучэнні клавіш"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Выдаліць спалучэнне клавіш?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Скінуць налады да стандартных?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Націсніце клавішу, каб прызначыць спалучэнне клавіш"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Каб стварыць гэта спалучэнне клавіш, націсніце клавішу дзеяння разам з яшчэ адной ці некалькімі клавішамі"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Гэта дзеянне назаўсёды выдаліць прызначанае вамі спалучэнне клавіш."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Усе карыстальніцкія спалучэнні клавіш будуць назаўсёды выдалены."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пошук спалучэнняў клавіш"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Так, скінуць"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Скасаваць"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Націсніце клавішу"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Гэта спалучэнне клавіш ужо выкарыстоўваецца. Паспрабуйце іншую клавішу."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Гэта спалучэнне клавіш ужо выкарыстоўваецца. Паспрабуйце іншае спалучэнне."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Не ўдаецца наладзіць спалучэнне клавіш."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Дадаць ярлык"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Назад"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"На галоўную старонку"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Прагляд нядаўніх праграм"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Пераключэнне праграм"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Гатова"</string> <string name="gesture_error_title" msgid="469064941635578511">"Паспрабуйце яшчэ раз!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Выдатная праца!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Вы скончылі вывучэнне жэсту для прагляду нядаўніх праграм."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Каб праглядзець нядаўнія праграмы, правядзіце трыма пальцамі ўверх па сэнсарным экране і затрымайце пальцы"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Пераключэнне праграм"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Выдатная праца!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Вы навучыліся рабіць жэст пераключэння праграм."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Глядзець усе праграмы"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Націсніце клавішу дзеяння на клавіятуры"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Выдатна!"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 95037ab4d29e..245711f831b5 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Актуализира се"</string> <string name="status_bar_work" msgid="5238641949837091056">"Потребителски профил в Work"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Самолетен режим"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Няма да чуете следващия си будилник в <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"в <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"в/ъв <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Сателит, добра връзка"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Сателит, налице е връзка"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS чрез сателит"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Само спешни обаждания или SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"няма сигнал"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"една чертичка"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Назад"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Известия"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Клавишни комбинации"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Превкл. на клавиат. подредба"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"или"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Изчистване на заявката за търсене"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Клавишни комбинации"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системни приложения"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Няколко задачи едновременно"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Разделен екран"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Въвеждане"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Преки пътища към приложения"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Текущо приложение"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Персонализиране на преките пътища"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Да се премахне ли клавишната комбинация?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Да се възстановят ли стандартните настройки?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Натиснете клавиш, за да зададете клавишна комбинация"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"За да създадете тази клавишна комбинация, натиснете клавиша за действия заедно с един или повече други клавиши"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Това ще изтрие персонализираната клавишна комбинация за постоянно."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Това ще изтрие всичките ви персонализирани преки пътища за постоянно."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Търсете клавишни комбинации"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Да, нулиране"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Отказ"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Натиснете клавиш"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Клавишната комбинация вече се използва. Опитайте с друг клавиш."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Клавишната комбинация вече се използва. Опитайте с друга."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Прекият път не може да се зададе."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Добавяне на пряк път"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Назад"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Към началния екран"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Преглед на скорошните приложения"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Превключване на приложенията"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string> <string name="gesture_error_title" msgid="469064941635578511">"Опитайте отново!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Отлично!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Изпълнихте жеста за преглед на скорошните приложения."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"За да прегледате скорошните приложения, плъзнете три пръста нагоре по сензорния панел и задръжте"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Превключване на приложенията"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Отлично!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Изпълнихте жеста за превключване между приложения."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Преглед на всички приложения"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Натиснете клавиша за действия на клавиатурата си"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Браво!"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 73eddf28bbed..42a4d540c0c8 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"আপডেট করা হচ্ছে"</string> <string name="status_bar_work" msgid="5238641949837091056">"কাজের প্রোফাইল"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"বিমান মোড"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"আপনি আপনার পরবর্তী <xliff:g id="WHEN">%1$s</xliff:g> অ্যালার্ম শুনতে পাবেন না"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> -তে"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"স্যাটেলাইট, ভালো কানেকশন"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"স্যাটেলাইট, কানেকশন উপলভ্য আছে"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"স্যাটেলাইট SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"শুধুমাত্র জরুরি কল বা SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>।"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"কোনও সিগন্যাল নেই"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"একটি বার"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"পিছনে"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"বিজ্ঞপ্তি"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"কীবোর্ড শর্টকাট"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"কীবোর্ড লে-আউট পাল্টান"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"অথবা"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"সার্চ কোয়েরি মুছুন"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"কীবোর্ড শর্টকাট"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"সিস্টেম অ্যাপ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"মাল্টিটাস্কিং"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"স্প্লিট স্ক্রিন"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ইনপুট"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"অ্যাপ শর্টকাট"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"বর্তমান অ্যাপ"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"শর্টকাট কাস্টমাইজ করুন"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"শর্টকাট সরাবেন?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ডিফল্ট শর্টকার্ট আবার রিসেট করতে চান?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"শর্টকাট অ্যাসাইন করতে কী প্রেস করুন"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"এই শর্টকার্ট তৈরি করতে, অ্যাকশন \'কী\' এবং এক বা আরও বেশি \'কী\' একসাথে প্রেস করুন"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"এটি আপনার কাস্টম শর্টকাট স্থায়ীভাবে মুছে ফেলবে।"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"এটি আপনার সব কাস্টম শর্টকার্ট স্থায়ীভাবে মুছে দেবে।"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"শর্টকাট সার্চ করুন"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"হ্যাঁ, রিসেট করতে চাই"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"বাতিল করুন"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"কী প্রেস করুন"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"কী কম্বিনেশন আগে থেকে ব্যবহার হচ্ছে। অন্য কী ব্যবহার করে দেখুন।"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"\'কী\' শর্টকার্ট আগে থেকে ব্যবহার হচ্ছে। অন্য শর্টকার্ট ব্যবহার করে দেখুন।"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"শর্টকাট সেট করা যায়নি।"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"শর্টকাট যোগ করুন"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ফিরে যান"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"হোমে যান"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপ দেখুন"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"অ্যাপ পরিবর্তন করুন"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"হয়ে গেছে"</string> <string name="gesture_error_title" msgid="469064941635578511">"আবার চেষ্টা করুন!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ফিরে যান"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"অসাধারণ!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপের জেসচার দেখা সম্পূর্ণ করেছেন।"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"সাম্প্রতিক অ্যাপ দেখতে, নিজের টাচপ্যাডে তিনটি আঙুল ব্যবহার করে উপরের দিকে সোয়াইপ করে হোল্ড করুন"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"অ্যাপ পরিবর্তন করুন"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"অসাধারণ!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"আপনি অ্যাপ পরিবর্তন করার জেসচার সম্পূর্ণ করেছেন।"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"সব অ্যাপ দেখুন"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"আপনার কীবোর্ডে অ্যাকশন কী প্রেস করুন"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"দারুণ!"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index c16627f86820..69f163512987 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ažuriranje"</string> <string name="status_bar_work" msgid="5238641949837091056">"Radni profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u avionu"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobra veza"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Hitna pomoć putem satelita"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Samo hitni pozivi ili pomoć"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"nema signala"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"jedna crtica"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Nazad"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Obavještenja"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Prečice tastature"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Zamijeni raspored tastature"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ili"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Brisanje upita za pretraživanje"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Prečice na tastaturi"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistemske aplikacije"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Podijeljeni ekran"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Unos"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Prečice aplikacije"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Trenutna aplikacija"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Prilagodite prečice"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Ukloniti prečicu?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vratiti na zadano?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite tipku da dodijelite prečicu"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Da kreirate ovu prečicu, istovremeno pritisnite tipku radnji i jednu ili više tipki"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Ovo će trajno izbrisati prilagođenu prečicu."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Ovo će trajno izbrisati sve vaše prilagođene prečice."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pretražite prečice"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Da, vrati na zadano"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Otkaži"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipku"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ta se kombinacija tipki već koristi. Pokušajte s drugom tipkom."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Ta se kombinacija tipki već koristi. Pokušajte s drugom kombinacijom."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Prečica se ne može postaviti."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Dodavanje prečice"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Nazad"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Odlazak na početni ekran"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Prikaži nedavne aplikacije"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Promijenite aplikaciju"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string> <string name="gesture_error_title" msgid="469064941635578511">"Pokušajte ponovo!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Sjajno!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvršili ste pokret za prikaz nedavnih aplikacija."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Da pogledate nedavne aplikacije, prevucite nagore i zadržite s tri prsta na dodirnoj podlozi"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Promijenite aplikaciju"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Sjajno!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Izvršili ste pokret za promjenu aplikacije."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Pogledajte sve aplikacije"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipku radnji na tastaturi"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 43ba8fac3dad..d90c4fffd5aa 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"S\'està actualitzant"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de treball"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode d\'avió"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> no sentiràs la pròxima alarma"</string> <string name="alarm_template" msgid="2234991538018805736">"Hora: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"Dia: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satèl·lit, bona connexió"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satèl·lit, connexió disponible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS per satèl·lit"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Només SOS o trucades d\'emergència"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"no hi ha senyal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Enrere"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notificacions"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Tecles de drecera"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Canvia disposició de teclat"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"o"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Esborra la consulta de cerca"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tecles de drecera"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplicacions del sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasca"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Pantalla dividida"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Dreceres d\'aplicacions"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicació actual"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalitza les dreceres"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Vols suprimir la drecera?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vols restablir els valors predeterminats?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Prem la tecla per assignar la drecera"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Per crear aquesta drecera, prem la tecla d\'acció i una o més tecles alhora"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Aquesta acció suprimirà la drecera personalitzada permanentment."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Aquesta acció suprimirà totes les dreceres personalitzades permanentment."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Dreceres de cerca"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sí, restableix"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel·la"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Prem una tecla"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"La combinació de tecles ja s\'està utilitzant. Prova-ho amb una altra tecla."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"La combinació de tecles ja s\'està utilitzant. Prova-ho amb una altra combinació."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"No es pot configurar la drecera."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Afegeix una drecera"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Torna"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ves a la pantalla d\'inici"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Mostra les aplicacions recents"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Canviar d\'aplicació"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fet"</string> <string name="gesture_error_title" msgid="469064941635578511">"Torna-ho a provar"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Torna"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Ben fet!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Has completat el gest per veure les aplicacions recents."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Per veure les aplicacions recents, llisca cap amunt amb tres dits i mantén-los premuts al ratolí tàctil"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Canviar d\'aplicació"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Ben fet!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Has completat el gest per canviar d\'aplicació."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Mostra totes les aplicacions"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Prem la tecla d\'acció al teclat"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Enhorabona!"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 17945a3856d6..2cfc4dab8e48 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Probíhá aktualizace"</string> <string name="status_bar_work" msgid="5238641949837091056">"Pracovní profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Režim Letadlo"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Svůj další budík <xliff:g id="WHEN">%1$s</xliff:g> neuslyšíte"</string> <string name="alarm_template" msgid="2234991538018805736">"v <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobré připojení"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, připojení je k dispozici"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS přes satelit"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Pouze tísňové hovory nebo SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"není signál"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"jedna čárka"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Zpět"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Oznámení"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Klávesové zkratky"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Přepnout rozložení klávesnice"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"nebo"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Vymazat vyhledávaný dotaz"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Klávesové zkratky"</string> @@ -1432,16 +1432,17 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Systémové aplikace"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Rozdělená obrazovka"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Vstup"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Zkratky aplikací"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuální aplikace"</string> <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Přístupnost"</string> <string name="shortcut_helper_title" msgid="8567500639300970049">"Klávesové zkratky"</string> - <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) --> - <skip /> + <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Přizpůsobení zkratek"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Odstranit zkratku?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Resetovat do výchozího nastavení?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Nastavte zkratku stisknutím klávesy"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"K vytvoření této zkratky stiskněte současně akční klávesu a jednu nebo více dalších kláves"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Vlastní zkratka se trvale smaže."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Tím trvale odstraníte všechny své vlastní zkratky."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Vyhledat zkratky"</string> @@ -1463,13 +1464,11 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ano, resetovat"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Zrušit"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Stiskněte klávesu"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinace kláves se už používá. Použijte jinou klávesu."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Kombinace kláves se už používá. Zkuste jinou kombinaci."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Zkratku není možné nastavit."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> - <!-- no translation found for shortcut_helper_add_shortcut_button_label (7655779534665954910) --> - <skip /> - <!-- no translation found for shortcut_helper_delete_shortcut_button_label (3148773472696137052) --> - <skip /> + <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Přidat zkratku"</string> + <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Smazat zkratku"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigujte pomocí klávesnice"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Naučte se klávesové zkratky"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigujte pomocí touchpadu"</string> @@ -1479,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Zpět"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Přejít na domovskou stránku"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Zobrazit nedávné aplikace"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Přepnout aplikace"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hotovo"</string> <string name="gesture_error_title" msgid="469064941635578511">"Zkuste to znovu."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zpět"</string> @@ -1496,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Výborně!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Provedli jste gesto pro zobrazení nedávných aplikací."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Pokud chcete zobrazit poslední aplikace, přejeďte na touchpadu třemi prsty nahoru a podržte je"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Přepnout aplikace"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Výborně!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Dokončili jste gesto přepínání aplikací."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Zobrazit všechny aplikace"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Stiskněte akční klávesu na klávesnici"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Výborně!"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 1f8c8659b9cf..29961e340408 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Opdaterer"</string> <string name="status_bar_work" msgid="5238641949837091056">"Arbejdsprofil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flytilstand"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Du vil ikke kunne høre din næste alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"på <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellit – god forbindelse"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit – forbindelsen er tilgængelig"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-meldinger via satellit"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Kun nødopkald eller SOS-meldinger via satellit"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"intet signal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"én bjælke"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Tilbage"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notifikationer"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Tastaturgenveje"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Skift tastaturlayout"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"eller"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Ryd søgeforespørgsel"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tastaturgenveje"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Systemapps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Opdelt skærm"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Appgenveje"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuel app"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Tilpas genveje"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Skal genvejen fjernes?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vil du nulstille til standard?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tryk på en tast for at tildele genvej"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Opret denne genvej ved at trykke på handlingstasten og én eller flere andre taster samtidigt"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Denne handling sletter din tilpassede genvej permanent."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Denne handling sletter alle dine tilpassede genveje permanent."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Søg efter genveje"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ja, nulstil"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuller"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tryk på en tast"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tastekombinationen er allerede i brug. Prøv en anden tast."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Tastekombinationen er allerede i brug. Prøv en anden kombination."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Genvejen kan ikke konfigureres."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Tilføj genvej"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Gå tilbage"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Gå til startsiden"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se seneste apps"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Skift mellem apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Udfør"</string> <string name="gesture_error_title" msgid="469064941635578511">"Prøv igen!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbage"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Godt klaret!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du har udført bevægelsen for at se de seneste apps."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Du kan se nyligt brugte apps ved at stryge opad og holde tre fingre nede på touchpladen"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Skift mellem apps"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Godt klaret!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Du har fuldført bevægelsen for at skifte mellem apps."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Se alle apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tryk på handlingstasten på dit tastatur"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Flot klaret!"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 213955839a71..2e452dda0f34 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Wird aktualisiert…"</string> <string name="status_bar_work" msgid="5238641949837091056">"Arbeitsprofil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flugmodus"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Lautloser Weckruf <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"um <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"am <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellit, Verbindung gut"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit, Verbindung verfügbar"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Notruf über Satellit"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Nur Notrufe oder SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"kein Empfang"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"ein Balken"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Zurück"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Benachrichtigungen"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Tastenkürzel"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Tastaturlayout wechseln"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"oder"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Suchanfrage löschen"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tastenkombinationen"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"System-Apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Splitscreen"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Eingabe"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Tastaturkürzel für Apps"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuelle App"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Tastenkombinationen anpassen"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Tastaturkürzel entfernen?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Auf Standardeinstellung zurücksetzen?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Drücke eine Taste, um das Tastaturkürzel einzurichten"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Drücke zum Erstellen der Tastenkombination gleichzeitig die Aktionstaste und eine oder mehrere andere Tasten"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Das benutzerdefinierte Tastenkürzel wird endgültig gelöscht."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Alle deine benutzerdefinierten Tastenkürzel werden endgültig gelöscht."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tastenkürzel suchen"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ja, zurücksetzen"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Abbrechen"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Taste drücken"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Diese Tastenkombination wird bereits verwendet. Versuche es mit einer anderen Taste."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Diese Tastenkombination wird bereits verwendet. Versuche es mit einer anderen Kombination."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Die Tastenkombination kann nicht festgelegt werden."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Verknüpfung hinzufügen"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Zurück"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Zum Startbildschirm"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Letzte Apps aufrufen"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Zwischen Apps wechseln"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fertig"</string> <string name="gesture_error_title" msgid="469064941635578511">"Noch einmal versuchen"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zurück"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Gut gemacht!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du hast das Tutorial für die Touch-Geste zum Aufrufen der zuletzt verwendeten Apps abgeschlossen."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Wenn du zuletzt verwendete Apps aufrufen möchtest, wische mit drei Fingern nach oben und halte das Touchpad gedrückt"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Zwischen Apps wechseln"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Gut gemacht!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Du hast die Touch-Geste „Zwischen Apps wechseln\" abgeschlossen."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Alle Apps anzeigen"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Drücke die Aktionstaste auf deiner Tastatur"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Perfekt!"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 589298ea616b..c5aa667e9c74 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ενημέρωση"</string> <string name="status_bar_work" msgid="5238641949837091056">"Προφίλ εργασίας"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Λειτουργία πτήσης"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Δεν θα ακούσετε το επόμενο ξυπνητήρι σας <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"στις <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"στις <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Δορυφορική, καλή σύνδεση"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Δορυφορική, διαθέσιμη σύνδεση"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Δορυφορικό SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Μόνο κλήσεις έκτακτης ανάγκης ή SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"δεν υπάρχει σήμα"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"μία γραμμή"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Πίσω"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Ειδοποιήσεις"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Συντομεύσεις πληκτρολογίου"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Αλλαγή διάταξης πληκτρολογίου"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ή"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Διαγραφή ερωτήματος αναζήτησης"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Συντομεύσ. πληκτρολογίου"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Εφαρμογές συστήματος"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Πολυδιεργασία"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Διαχωρισμός οθόνης"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Εισαγωγή"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Συντομεύσεις εφαρμογών"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Τρέχουσα εφαρμογή"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Προσαρμογή συντομεύσεων"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Κατάργηση συντόμευσης;"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Επαναφορά στις προεπιλογές;"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Πατήστε το πλήκτρο για ανάθεση της συντόμευσης"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Για να δημιουργήσετε αυτή τη συντόμευση, πατήστε ταυτόχρονα το πλήκτρο ενέργειας και ένα ή περισσότερα άλλα πλήκτρα"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Με αυτή την ενέργεια, η προσαρμοσμένη συντόμευση θα διαγραφεί οριστικά."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Με αυτή την ενέργεια θα διαγραφούν οριστικά όλες οι προσαρμοσμένες συντομεύσεις."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Συντομεύσεις αναζήτησης"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ναι, επαναφορά"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Ακύρωση"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Πατήστε ένα πλήκτρο"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ο συνδυασμός πλήκτρων χρησιμοποιείται ήδη. Δοκιμάστε άλλο πλήκτρο."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Ο συνδυασμός πλήκτρων χρησιμοποιείται ήδη. Δοκιμάστε έναν άλλο συνδυασμό."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Δεν είναι δυνατή η ρύθμιση της συντόμευσης."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Προσθήκη συντόμευσης"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Επιστροφή"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Αρχική"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Προβολή πρόσφατων εφαρμογών"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Εναλλαγή μεταξύ εφαρμογών"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Τέλος"</string> <string name="gesture_error_title" msgid="469064941635578511">"Δοκιμάστε ξανά!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Επιστροφή"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Μπράβο!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ολοκληρώσατε την κίνηση για την προβολή πρόσφατων εφαρμογών."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Για προβολή πρόσφατων εφαρμογών, σύρετε προς τα επάνω με τρία δάχτυλα και κρατήστε τα δάχτυλά σας στην επιφάνεια αφής"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Εναλλαγή μεταξύ εφαρμογών"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Μπράβο!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ολοκληρώσατε την κίνηση εναλλαγής εφαρμογών."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Προβολή όλων των εφαρμογών"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Πατήστε το πλήκτρο ενέργειας στο πληκτρολόγιό σας"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Μπράβο!"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index f31e51f7f3da..4144dc300a58 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Updating"</string> <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, good connection"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Emergency calls or SOS only"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"No signal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Back"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notifications"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Keyboard shortcuts"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Switch keyboard layout"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"or"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Clear search query"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Keyboard shortcuts"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"System apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Split screen"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App shortcuts"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current app"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Customise shortcuts"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remove shortcut?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Reset back to default?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Press key to assign shortcut"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"To create this shortcut, press the action key and one or more other keys together"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"This will delete your custom shortcut permanently."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"This will delete all your custom shortcuts permanently."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Yes, reset"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Press key"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Key combination already in use. Try another key."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Key combination already in use. Try another combination."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Shortcut cannot be set."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Add shortcut"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Go back"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Switch apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string> <string name="gesture_error_title" msgid="469064941635578511">"Try again."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"To view recent apps, swipe up and hold using three fingers on your touchpad"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Switch apps"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Well done!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"You completed the switch apps gesture."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index be09504a5cd6..b00b01d373f3 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -750,6 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Updating"</string> <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Airplane mode"</string> + <string name="status_bar_supervision" msgid="6735015942701134125">"Parental controls"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +760,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, good connection"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Emergency calls or SOS only"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"no signal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string> @@ -857,7 +857,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Back"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notifications"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Keyboard Shortcuts"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Switch keyboard layout"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"or"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Clear search query"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Keyboard Shortcuts"</string> @@ -1432,6 +1431,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"System apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Split screen"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App shortcuts"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current App"</string> @@ -1440,7 +1441,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Customize shortcuts"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remove shortcut?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Reset back to default?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Press key to assign shortcut"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"To create this shortcut, press the Action key and one or more other keys together"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"This will delete your custom shortcut permanently."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"This will delete all your custom shortcuts permanently."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string> @@ -1462,7 +1463,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Yes, reset"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Press key"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Key combination already in use. Try another key."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Key combination already in use. Try another combination."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Shortcut cannot be set."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Add shortcut"</string> @@ -1476,6 +1477,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Go back"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Switch apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string> <string name="gesture_error_title" msgid="469064941635578511">"Try again!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string> @@ -1493,6 +1495,11 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Great job!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"To view recent apps, swipe up and hold using three fingers on your touchpad"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Switch apps"</string> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2751565200937541667">"Swipe left using four fingers on your touchpad"</string> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Great job!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"You completed the switch apps gesture."</string> + <string name="touchpad_switch_gesture_error_body" msgid="5508381152326379652">"Swipe left using four fingers on your touchpad to switch apps"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index f31e51f7f3da..4144dc300a58 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Updating"</string> <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, good connection"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Emergency calls or SOS only"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"No signal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Back"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notifications"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Keyboard shortcuts"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Switch keyboard layout"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"or"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Clear search query"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Keyboard shortcuts"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"System apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Split screen"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App shortcuts"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current app"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Customise shortcuts"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remove shortcut?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Reset back to default?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Press key to assign shortcut"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"To create this shortcut, press the action key and one or more other keys together"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"This will delete your custom shortcut permanently."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"This will delete all your custom shortcuts permanently."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Yes, reset"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Press key"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Key combination already in use. Try another key."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Key combination already in use. Try another combination."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Shortcut cannot be set."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Add shortcut"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Go back"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Switch apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string> <string name="gesture_error_title" msgid="469064941635578511">"Try again."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"To view recent apps, swipe up and hold using three fingers on your touchpad"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Switch apps"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Well done!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"You completed the switch apps gesture."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index f31e51f7f3da..4144dc300a58 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Updating"</string> <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, good connection"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, connection available"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Emergency calls or SOS only"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"No signal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"one bar"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Back"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notifications"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Keyboard shortcuts"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Switch keyboard layout"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"or"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Clear search query"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Keyboard shortcuts"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"System apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Split screen"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App shortcuts"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current app"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Customise shortcuts"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remove shortcut?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Reset back to default?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Press key to assign shortcut"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"To create this shortcut, press the action key and one or more other keys together"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"This will delete your custom shortcut permanently."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"This will delete all your custom shortcuts permanently."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Yes, reset"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Press key"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Key combination already in use. Try another key."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Key combination already in use. Try another combination."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Shortcut cannot be set."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Add shortcut"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Go back"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Go home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Switch apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string> <string name="gesture_error_title" msgid="469064941635578511">"Try again."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Well done!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"To view recent apps, swipe up and hold using three fingers on your touchpad"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Switch apps"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Well done!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"You completed the switch apps gesture."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index dacea9ff1b61..85ff751d28ec 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Actualizando"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avión"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma a la(s) <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"a la(s) <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"el <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, buena conexión"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexión disponible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS por satélite"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Solo llamadas de emergencia o SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"sin señal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Atrás"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notificaciones"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Ver combinaciones de teclas"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Cambiar diseño del teclado"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"o"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Borrar búsqueda"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Combinaciones de teclas"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apps del sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Tareas múltiples"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Pantalla dividida"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Accesos directos a aplicaciones"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App actual"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar combinaciones de teclas"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"¿Quieres quitar la combinación?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"¿Quieres restablecer la configuración predeterminada?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Presiona una tecla para asignar la combinación"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Para crear esta combinación de teclas, presiona la tecla de acción y una o más teclas"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Esta acción borrará tu combinación personalizada de forma permanente."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Esta acción borrará todas tus combinaciones personalizadas de forma permanente."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Buscar combinaciones de teclas"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sí, restablecer"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Presiona una tecla"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"La combinación de teclas ya está en uso. Prueba con otra."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"La combinación de teclas ya está en uso. Prueba con otra combinación."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"No se puede establecer la combinación de teclas."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Agregar combinación de teclas"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Atrás"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir a la página principal"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver apps recientes"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Cambiar de app"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Listo"</string> <string name="gesture_error_title" msgid="469064941635578511">"Vuelve a intentarlo"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atrás"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"¡Bien hecho!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Completaste el gesto para ver las apps recientes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Para ver las apps recientes, desliza tres dedos hacia arriba y mantenlos presionados en el panel táctil"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Cambia de app"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"¡Bien hecho!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Completaste el gesto para cambiar de app."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todas las apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Presiona la tecla de acción en el teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"¡Bien hecho!"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 1799055627c1..62c629074ce1 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Actualizando"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo Avión"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string> <string name="alarm_template" msgid="2234991538018805736">"a las <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, buena conexión"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexión disponible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS por satélite"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Solo llamadas de emergencia o SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"no hay señal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Atrás"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notificaciones"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Ver combinaciones de teclas"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Cambiar diseño del teclado"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"o"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Borrar la consulta de búsqueda"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Combinaciones de teclas"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplicaciones del sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarea"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Pantalla dividida"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Accesos directos a aplicaciones"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicación en uso"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar combinaciones de teclas"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"¿Eliminar combinación de teclas?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"¿Restablecer valores predeterminados?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pulsa una tecla para asignar una combinación de teclas"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Para crear esta combinación de teclas, pulsa la tecla de acción y una o varias teclas a la vez"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Se eliminará tu combinación de teclas personalizada de forma permanente."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Se eliminarán todos tus accesos directos personalizados de forma permanente."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Buscar accesos directos"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sí, restablecer"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pulsa una tecla"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"La combinación de teclas ya se está usando. Prueba con otra tecla."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"La combinación de teclas ya se está usando. Prueba con otra combinación."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"No se puede configurar la combinación de teclas."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Añadir combinación de teclas"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Volver"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir a Inicio"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver aplicaciones recientes"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Cambiar de aplicación"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hecho"</string> <string name="gesture_error_title" msgid="469064941635578511">"Vuelve a intentarlo."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atrás"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"¡Bien hecho!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Has completado el gesto para ver las aplicaciones recientes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Para ver las aplicaciones recientes, desliza tres dedos hacia arriba y mantén pulsado en el panel táctil"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Cambiar de aplicación"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"¡Bien hecho!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Has completado el gesto para cambiar de aplicación."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todas las aplicaciones"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pulsa la tecla de acción de tu teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"¡Muy bien!"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index a91e3dcc7b2f..920af5c4d353 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Värskendamine"</string> <string name="status_bar_work" msgid="5238641949837091056">"Tööprofiil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lennukirežiim"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Te ei kuule järgmist äratust kell <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"kell <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"kell <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliit, hea ühendus"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliit, ühendus on saadaval"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelliit-SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Ainult hädaabikõned või satelliit-SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"signaal puudub"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"üks pulk"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Tagasi"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Märguanded"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Klaviatuuri otseteed"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Klaviatuuripaigutuse vahetus"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"või"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Otsingupäringu tühjendamine"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Klaviatuuri otseteed"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Süsteemirakendused"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitegumtöö"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Jagatud ekraanikuva"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Sisend"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Rakenduse otseteed"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Praegune rakendus"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Otseteede kohandamine"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Kas soovite otsetee eemaldada?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Kas lähtestada vaikeseadele?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Otsetee lisamiseks vajutage klahvi"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Selle otsetee loomiseks vajutage toiminguklahvi ja ühte või mitut muud klahvi korraga."</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"See kustutab teie kohandatud otsetee jäädavalt."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"See kustutab kõik teie kohandatud otseteed jäädavalt."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Otsige otseteid"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Lähtesta"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Tühista"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Vajutage klahvi"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinatsioon on juba kasutusel. Proovige mõnda muud klahvi."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Kombinatsioon on juba kasutusel. Proovige mõnda muud kombinatsiooni."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Otseteed ei saa seadistada."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Otsetee lisamine"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Mine tagasi"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Avakuvale"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Hiljutiste rakenduste vaatamine"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Rakenduste vahetamine"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Valmis"</string> <string name="gesture_error_title" msgid="469064941635578511">"Proovige uuesti!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tagasi"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Väga hea!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Tegite hiljutiste rakenduste vaatamise liigutuse."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Hiljutiste rakenduste kuvamiseks pühkige puuteplaadil kolme sõrmega üles ja hoidke sõrmi puuteplaadil"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Rakenduste vahetamine"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Väga hea!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Tegite rakenduste vahetamise liigutuse."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Kõigi rakenduste kuvamine"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Vajutage klaviatuuril toiminguklahvi"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Hästi tehtud!"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 3a3c9cc144a6..912da58efc44 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Eguneratzen"</string> <string name="status_bar_work" msgid="5238641949837091056">"Laneko profila"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Hegaldi modua"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ez duzu entzungo hurrengo alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string> <string name="alarm_template" msgid="2234991538018805736">"ordua: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"data: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelitea, konexio ona"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelitea, konexioa erabilgarri"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelite bidezko SOS komunikazioa"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Larrialdi-deiak edo SOS komunikazioa soilik"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ez dago seinalerik"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"barra bat"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Atzera"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Jakinarazpenak"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Lasterbideak"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Aldatu tekl. diseinua"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"edo"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Garbitu bilaketa-kontsulta"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Lasterbideak"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistemaren aplikazioak"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Zeregin bat baino gehiago aldi berean exekutatzea"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Pantaila zatitzea"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Sarrera"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Aplikazioetarako lasterbideak"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Oraingo aplikazioa"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Pertsonalizatu lasterbideak"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Lasterbidea kendu nahi duzu?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Balio lehenetsia berrezarri nahi duzu?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Sakatu tekla lasterbidea esleitzeko"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Lasterbide hau sortzeko, sakatu ekintza-tekla eta beste tekla bat edo gehiago batera"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Betiko ezabatuko da lasterbide pertsonalizatua."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Lasterbide pertsonalizatu guztiak betiko ezabatuko dira."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Bilatu lasterbideak"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Bai, berrezarri"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Utzi"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Sakatu tekla"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tekla-konbinazio hori erabili da dagoeneko. Probatu beste tekla bat."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Tekla-konbinazio hori erabili da dagoeneko. Probatu beste konbinazio batekin."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Ezin da ezarri lasterbidea."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Gehitu lasterbide bat"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Egin atzera"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Joan orri nagusira"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ikusi azkenaldiko aplikazioak"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Aldatu aplikazioa"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Eginda"</string> <string name="gesture_error_title" msgid="469064941635578511">"Saiatu berriro!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Egin atzera"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bikain!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Osatu duzu azkenaldiko aplikazioak ikusteko keinua."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Azkenaldiko aplikazioak ikusteko, pasatu 3 hatz gora eta eduki sakatuta ukipen-panelean"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Aldatu aplikazioa"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bikain!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ikasi duzu aplikazio batetik bestera aldatzeko keinua."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ikusi aplikazio guztiak"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Sakatu teklatuko ekintza-tekla"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bikain!"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 2caaf1415470..3612b16de761 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -167,7 +167,7 @@ <string name="issuerecord_start_error" msgid="3402782952722871190">"هنگام شروع ضبط مشکل، خطایی پیش آمد"</string> <string name="immersive_cling_title" msgid="8372056499315585941">"درحال مشاهده در حالت تمامصفحه"</string> <string name="immersive_cling_description" msgid="2717426731830851921">"برای خروج، از بالای صفحه تند به پایین بکشید"</string> - <string name="immersive_cling_positive" msgid="3076681691468978568">"متوجهام"</string> + <string name="immersive_cling_positive" msgid="3076681691468978568">"متوجهم"</string> <string name="accessibility_back" msgid="6530104400086152611">"برگشت"</string> <string name="accessibility_home" msgid="5430449841237966217">"صفحهٔ اصلی"</string> <string name="accessibility_menu" msgid="2701163794470513040">"منو"</string> @@ -534,7 +534,7 @@ <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"افزایش ارتفاع"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ابزارههای صفحه قفل"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"برای باز کردن برنامه بااستفاده از ابزاره، باید هویت خودتان را بهتأیید برسانید. همچنین، بهخاطر داشته باشید که همه میتوانند آنها را مشاهده کنند، حتی وقتی رایانه لوحیتان قفل است. برخیاز ابزارهها ممکن است برای صفحه قفل درنظر گرفته نشده باشند و ممکن است اضافه کردن آنها در اینجا ناامن باشد."</string> - <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"متوجهام"</string> + <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"متوجهم"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ابزارهها"</string> <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"برای افزودن میانبر «ابزارهها»، مطمئن شوید «نمایش ابزارهها در صفحه قفل» در تنظیمات فعال باشد."</string> <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"تنظیمات"</string> @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"درحال بهروزرسانی"</string> <string name="status_bar_work" msgid="5238641949837091056">"نمایه کاری"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"حالت هواپیما"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"در ساعت <xliff:g id="WHEN">%1$s</xliff:g>، دیگر صدای زنگ ساعت را نمیشنوید"</string> <string name="alarm_template" msgid="2234991538018805736">"در <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"در <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ماهواره، اتصال خوب است"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ماهواره، اتصال دردسترس است"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"درخواست کمک ماهوارهای"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"فقط تماس اضطراری یا درخواست کمک اضطراری"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>، <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"سیگنال وجود ندارد"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"یک خط"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"برگشت"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"اعلانها"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"میانبرهای صفحهکلید"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"تغییر جانمایی صفحهکلید"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"یا"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"پاک کردن پُرسمان جستجو"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"میانبرهای صفحهکلید"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"برنامههای سیستم"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"چندوظیفگی"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"صفحهٔ دونیمه"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ورودی"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"میانبرهای برنامه"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"برنامه فعلی"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"سفارشیسازی میانبرها"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"میانبر حذف شود؟"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"به تنظیم پیشفرض بازنشانی میکنید؟"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"برای اختصاص دادن میانبر، کلید را فشار دهید"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"برای ایجاد این میانبر، دکمه «کنش» و یک یا چند دکمه دیگر را همزمان فشار دهید."</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"با این کار، میانبر سفارشی شما برای همیشه حذف میشود."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"با این کار، همه میانبرهای سفارشی برای همیشه حذف خواهند شد."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"جستجوی میانبرها"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"بله، بازنشانی شود"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"لغو"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"کلید را فشار دهید"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"ترکیب کلید ازقبل درحال استفاده است. کلید دیگری را امتحان کنید."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"ترکیب کلید ازقبل درحال استفاده است. ترکیب دیگری را امتحان کنید."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"میانبر تنظیم نشد."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"افزودن میانبر"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"برگشتن"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"رفتن به صفحه اصلی"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"مشاهده برنامههای اخیر"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"جابهجایی بین برنامهها"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"تمام"</string> <string name="gesture_error_title" msgid="469064941635578511">"دوباره امتحان کنید!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"برگشتن"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"عالی است!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"اشاره «مشاهده برنامههای اخیر» را تمام کردید"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"برای مشاهده برنامههای اخیر، با سه انگشت روی صفحه لمسی تند بهبالا بکشید و نگه دارید"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"جابهجایی بین برنامهها"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"عالی است!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"اشاره جابهجایی بین برنامهها را تکمیل کردید."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"مشاهده همه برنامهها"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"دکمه کنش را روی صفحه لمسی فشار دهید"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"عالی بود!"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 0bd79100a959..9f1c72306b22 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -752,6 +752,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Päivitetään"</string> <string name="status_bar_work" msgid="5238641949837091056">"Työprofiili"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lentokonetila"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Et kuule seuraavaa hälytystäsi (<xliff:g id="WHEN">%1$s</xliff:g>)."</string> <string name="alarm_template" msgid="2234991538018805736">"kello <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ajankohtana <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -761,8 +763,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliitti, hyvä yhteys"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliitti, yhteys saatavilla"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Vain hätäpuhelut tai Satellite SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ei signaalia"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"yksi palkki"</string> @@ -859,7 +860,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Takaisin"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Ilmoitukset"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Pikanäppäimet"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Vaihda näppäimistöasettelu"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"tai"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Tyhjennä hakulauseke"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Pikanäppäimet"</string> @@ -1434,6 +1434,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Järjestelmäsovellukset"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitaskaus"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Jaettu näyttö"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Syöte"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Sovellusten pikakuvakkeet"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Nykyinen sovellus"</string> @@ -1442,7 +1444,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Muokkaa pikanäppäimiä"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Poistetaanko pikanäppäin?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Palautetaanko oletusasetukset?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Määritä pikanäppäin painamalla näppäintä"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Voit luoda tämän pikanäppäinyhdistelmän painamalla samaan aikaan toimintonäppäintä ja yhtä tai useampaa muuta näppäintä"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Oma pikanäppäin poistetaan pysyvästi."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Kaikki omat pikanäppäimet poistetaan pysyvästi."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pikahaut"</string> @@ -1464,7 +1466,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Kyllä, nollaa"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Peru"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Paina näppäintä"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Näppäinyhdistelmä on jo käytössä. Kokeile toista näppäintä."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Näppäinyhdistelmä on jo käytössä. Kokeile toista yhdistelmää."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Pikakuvaketta ei voi lisätä."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Lisää pikanäppäin"</string> @@ -1478,6 +1480,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Takaisin"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Siirry etusivulle"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Katso viimeisimmät sovellukset"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Vaihda sovellusta"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Valmis"</string> <string name="gesture_error_title" msgid="469064941635578511">"Yritä uudelleen."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Takaisin"</string> @@ -1495,6 +1498,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Hienoa!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Olet oppinut Katso viimeisimmät sovellukset ‑eleen."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Näet äskeiset sovellukset, kun pyyhkäiset ylös ja pidät kosketuslevyä painettuna kolmella sormella."</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Vaihda sovellusta"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Hienoa!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Olet oppinut sovelluksenvaihtoeleen."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Näytä kaikki sovellukset"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Paina näppäimistön toimintonäppäintä"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Hienoa!"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index f93ceb498f4c..6bcce5300d38 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Mise à jour en cours…"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme à <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"à <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"le <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Bonne connexion satellite"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Connexion satellite accessible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS par satellite"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Appels d\'urgence ou SOS seulement"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"aucun signal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"une barre"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Précédent"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notifications"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Raccourcis clavier"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Changer la disposition du clavier"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Effacez la requête de recherche"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Raccourcis-clavier"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Applis système"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitâche"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Écran divisé"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrée"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Raccourcis des applis"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Appli actuelle"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personnaliser les raccourcis"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Supprimer le raccourci?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Réinitialiser aux raccourcis par défaut?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Appuyez sur la touche pour attribuer un raccourci"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Pour créer ce raccourci, appuyez simultanément sur la touche d\'action et une ou plusieurs autres touches"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Cela supprimera définitivement votre raccourci personnalisé."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Cette action supprimera définitivement tous vos raccourcis personnalisés."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Rechercher des raccourcis"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Oui, réinitialiser"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuler"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Appuyez sur la touche"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"La combinaison de touches est déjà utilisée. Essayez une autre touche."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"La combinaison de touches est déjà utilisée. Essayez une autre combinaison."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Le raccourci ne peut pas être défini."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Ajouter un raccourci"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Retour"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Retour à la page d\'accueil"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Afficher les applis récentes"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Changer d\'appli"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"OK"</string> <string name="gesture_error_title" msgid="469064941635578511">"Réessayez!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bon travail!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Vous avez effectué le geste pour afficher les applis récentes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Pour afficher vos applis récentes, balayez votre pavé tactile vers le haut avec trois doigts et maintenez-les en place"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Changer d\'appli"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bon travail!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Vous avez terminé le geste de changement d\'appli."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Afficher toutes les applis"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Appuyez sur la touche d\'action de votre clavier"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Félicitations!"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index f0cc3b52fa02..33628260ff49 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Mise à jour"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>."</string> <string name="alarm_template" msgid="2234991538018805736">"à <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"le <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Bonne connexion satellite"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Connexion satellite disponible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS par satellite"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Appels d\'urgence ou SOS uniquement"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"aucun signal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"faible"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Précédent"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notifications"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Raccourcis clavier"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Changer disposition du clavier"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Effacer la requête de recherche"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Raccourcis clavier"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Applis système"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitâche"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Écran partagé"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Saisie"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Raccourcis d\'application"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Appli actuelle"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personnaliser les raccourcis"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Supprimer le raccourci ?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Rétablir les paramètres par défaut ?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Appuyez sur une touche pour attribuer un raccourci"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Pour créer ce raccourci, appuyez simultanément sur la touche d\'action et une ou plusieurs autres touches"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Votre raccourci personnalisé sera définitivement supprimé."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Tous vos raccourcis personnalisés seront définitivement supprimés."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Rechercher des raccourcis"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Oui, rétablir"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuler"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Appuyez sur la touche"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Combinaison de touches déjà utilisée. Essayez une autre touche."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Combinaison de touches déjà utilisée. Essayez une autre combinaison."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Impossible de définir le raccourci."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Ajouter un raccourci"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Retour"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Retour à l\'accueil"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Afficher les applis récentes"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Passer d\'une application à l\'autre"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"OK"</string> <string name="gesture_error_title" msgid="469064941635578511">"Essayez encore."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bravo !"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Vous avez appris le geste pour afficher les applis récentes"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Pour afficher les applis récentes, balayez le pavé tactile vers le haut avec trois doigts et maintenez la position"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Passer d\'une application à l\'autre"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bravo !"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Vous avez appris le geste pour passer d\'une appli à l\'autre."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Afficher toutes les applications"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Appuyez sur la touche d\'action de votre clavier"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bravo !"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index a449530050e5..60fe0b098d01 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Actualizando"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de traballo"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Non escoitarás a alarma seguinte <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"ás <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"o <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, boa conexión"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexión dispoñible"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS por satélite"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Só chamadas de emerxencia ou SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"non hai cobertura"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"unha barra"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Volver"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notificacións"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Atallos de teclado"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Cambiar deseño do teclado"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Borrar a busca"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Atallos de teclado"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplicacións do sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarefa"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Pantalla dividida"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atallos de aplicacións"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicación actual"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar os atallos"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Queres quitar o atallo?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Queres restablecer a opción predeterminada?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Preme a tecla para asignar o atallo"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Para crear este atallo, preme a tecla de acción e unha ou máis teclas á vez"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Eliminarase de forma permanente o teu atallo personalizado."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Eliminaranse permanentemente todos os teus atallos personalizados."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Busca atallos"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Si, restablecer"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Preme unha tecla"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Xa se está usando esta combinación de teclas. Proba con outra."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Xa se está usando esta combinación de teclas. Proba con outra."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Non se puido definir o atallo."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Engadir un atallo"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Volver"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir ao inicio"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Consultar aplicacións recentes"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Cambiar de aplicación"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Feito"</string> <string name="gesture_error_title" msgid="469064941635578511">"Téntao de novo."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Volver"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Moi ben!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Completaches o titorial do xesto de consultar aplicacións recentes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Para ver as aplicacións recentes, pasa tres dedos cara arriba e mantenos premidos no panel táctil"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Cambiar de aplicación"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bravo!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Completaches o xesto para cambiar de aplicación."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todas as aplicacións"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Preme a tecla de acción do teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Ben feito!"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 727d11248e8c..f9c5b81a615d 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"અપડેટ કરી રહ્યાં છીએ"</string> <string name="status_bar_work" msgid="5238641949837091056">"ઑફિસની પ્રોફાઇલ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"એરપ્લેન મોડ"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"તમે <xliff:g id="WHEN">%1$s</xliff:g> એ તમારો આગલો એલાર્મ સાંભળશો નહીં"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> વાગ્યે"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> એ"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"સૅટલાઇટ, સારું કનેક્શન"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"સૅટલાઇટ, કનેક્શન ઉપલબ્ધ છે"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ઇમર્જન્સી સૅટલાઇટ સહાય"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"માત્ર ઇમર્જન્સી કૉલ કે ઇમર્જન્સી સૅટલાઇટ સહાય"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"કોઈ સિગ્નલ નથી"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"એક બાર"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"પાછળ"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"નોટિફિકેશન"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"કીબોર્ડ શૉર્ટકટ"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"કીબોર્ડ લેઆઉટ સ્વિચ કરો"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"અથવા"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"શોધ ક્વેરી સાફ કરો"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"કીબોર્ડ શૉર્ટકટ"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"સિસ્ટમ ઍપ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"એકથી વધુ કાર્યો કરવા"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"સ્ક્રીનને વિભાજિત કરો"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ઇનપુટ"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ઍપ શૉર્ટકટ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"હાલની ઍપ"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"શૉર્ટકટ કસ્ટમાઇઝ કરો"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"શું શૉર્ટકટ કાઢી નાખીએ?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"પાછા ડિફૉલ્ટ પર રીસેટ કરીએ?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"શૉર્ટકટ સોંપવા માટે કી દબાવો"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"આ શૉર્ટકટ બનાવવા માટે, ઍક્શન કી અને એક કે તેથી વધુ કી એકસાથે દબાવો"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"આ તમારા કસ્ટમ શૉર્ટકટને કાયમી રીતે ડિલીટ કરશે."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"આ તમારા બધા કસ્ટમ શૉર્ટકટને કાયમ માટે ડિલીટ કરશે."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"શૉર્ટકટ શોધો"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"હા, રીસેટ કરો"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"રદ કરો"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"કી દબાવો"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"કી સંયોજન પહેલેલેથી ઉપયોગમાં છે. અન્ય કી અજમાવી જુઓ."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"કી સંયોજન પહેલેથી ઉપયોગમાં છે. અન્ય સંયોજન અજમાવી જુઓ."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"શૉર્ટકટ સેટ કરી શકાતો નથી."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"શૉર્ટકટ ઉમેરો"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"પાછા જાઓ"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"હોમ પર જાઓ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"તાજેતરની ઍપ જુઓ"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"ઍપ સ્વિચ કરો"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"થઈ ગયું"</string> <string name="gesture_error_title" msgid="469064941635578511">"ફરી પ્રયાસ કરો!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"પાછા જાઓ"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ખૂબ સરસ કામ!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"તમે \'તાજેતરની ઍપ જુઓ\' સંકેત પૂર્ણ કર્યો."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"તાજેતરની ઍપ જોવા માટે, તમારા ટચપૅડ પર ત્રણ આંગળી વડે ઉપરની તરફ સ્વાઇપ કરો અને દબાવી રાખો"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ઍપ સ્વિચ કરો"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ખૂબ સરસ કામ!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"તમે ઍપ સ્વિચ કરવાનો સંકેત પૂર્ણ કર્યો છે."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"બધી ઍપ જુઓ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"તમારા કીબોર્ડ પરની ઍક્શન કી દબાવો"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"વાહ!"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index f58512db0863..efb080ab0204 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"अपडेट हो रहा है"</string> <string name="status_bar_work" msgid="5238641949837091056">"वर्क प्रोफ़ाइल"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"फ़्लाइट मोड"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"आपको <xliff:g id="WHEN">%1$s</xliff:g> पर अपना अगला अलार्म नहीं सुनाई देगा"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> बजे"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> पर"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"सैटलाइट कनेक्शन अच्छा है"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"सैटलाइट कनेक्शन उपलब्ध है"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"सैटलाइट एसओएस"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"सिर्फ़ आपातकालीन कॉल या एसओएस का इस्तेमाल करें"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"सिग्नल नहीं है"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"एक सिग्नल बार"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"वापस जाएं"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"सूचनाएं"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"कीबोर्ड शॉर्टकट"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"कीबोर्ड लेआउट बदलें"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"या"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"सर्च क्वेरी साफ़ करें"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"कीबोर्ड शॉर्टकट"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"सिस्टम के ऐप्लिकेशन"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"मल्टीटास्किंग (एक साथ कई काम करना)"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"स्प्लिट स्क्रीन"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"इनपुट"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ऐप शॉर्टकट"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"मौजूदा ऐप्लिकेशन"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"पसंद के मुताबिक शॉर्टकट बनाएं"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"क्या आपको शॉर्टकट हटाना है?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"क्या आपको फिर से डिफ़ॉल्ट सेटिंग चालू करनी है?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"शॉर्टकट असाइन करने के लिए बटन दबाएं"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"यह शॉर्टकट बनाने के लिए, ऐक्शन बटन और एक या उससे ज़्यादा अन्य बटन एक साथ दबाएं"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ऐसा करने पर, पसंद के मुताबिक बनाया गया आपका शॉर्टकट हमेशा के लिए मिट जाएगा."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ऐसा करने पर, पसंद के मुताबिक बनाए गए आपके सभी शॉर्टकट हमेशा के लिए मिट जाएंगे."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"शॉर्टकट खोजें"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"हां, रीसेट करें"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"रद्द करें"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"बटन दबाएं"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"बटन का यह कॉम्बिनेशन पहले से इस्तेमाल किया जा रहा है. कोई दूसरा कॉम्बिनेशन आज़माएं."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"बटन का यह कॉम्बिनेशन पहले से इस्तेमाल किया जा रहा है. कोई दूसरा कॉम्बिनेशन आज़माएं."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"शॉर्टकट सेट नहीं किया जा सकता."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"शॉर्टकट जोड़ें"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"वापस जाएं"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"होम स्क्रीन पर जाएं"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखें"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"ऐप्लिकेशन के बीच स्विच करें"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"हो गया"</string> <string name="gesture_error_title" msgid="469064941635578511">"फिर से कोशिश करें!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"वापस जाएं"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"बहुत बढ़िया!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"अब आपको हाथ के जेस्चर का इस्तेमाल करके, हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखने का तरीका पता चल गया है."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखने के लिए, अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें और दबाकर रखें"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ऐप्लिकेशन के बीच स्विच करें"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"बहुत बढ़िया!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"आपने जान लिया है कि हाथ का जेस्चर इस्तेमाल करके ऐप्लिकेशन के बीच स्विच कैसे करें."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"सभी ऐप्लिकेशन देखें"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"अपने कीबोर्ड पर ऐक्शन बटन दबाएं"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"बहुत खूब!"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index b8b5f82dbf71..5078bfffeff9 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ažuriranje"</string> <string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u zrakoplovu"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobra veza"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, veza je dostupna"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS putem satelita"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Samo hitni pozivi ili SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"nema signala"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"jedna crtica"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Natrag"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Obavijesti"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Tipkovni prečaci"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Promjena rasporeda tipkovnice"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ili"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Brisanje upita za pretraživanje"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tipkovni prečaci"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplikacije sustava"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Obavljanje više zadataka"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Podijeljeni zaslon"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Unos"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Prečaci aplikacija"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Trenutačna aplikacija"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Prilagodite prečace"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Želite li ukloniti prečac?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Želite li vratiti na zadano?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite tipku da biste dodijelili prečac"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Da biste izradili taj prečac, pritisnite tipku za radnju i jednu ili više drugih tipki zajedno"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Time će se vaš prilagođeni prečac trajno izbrisati."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Time će se trajno izbrisati svi vaši prilagođeni prečaci."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečaci za pretraživanje"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Da, vrati"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Odustani"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipku"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ta se kombinacija već koristi. Pokušajte s nekom drugom."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Ta se kombinacija već koristi. Pokušajte s nekom drugom kombinacijom."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Prečac se ne može postaviti."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Dodaj prečac"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Natrag"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Na početni zaslon"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Pregled nedavnih aplikacija"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Promjena aplikacije"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string> <string name="gesture_error_title" msgid="469064941635578511">"Pokušajte ponovno!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Natrag"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Sjajno!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Napravili ste pokret za prikaz nedavno korištenih aplikacija."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Za prikaz nedavnih aplikacija prijeđite trima prstima prema gore na dodirnoj podlozi i zadržite pritisak"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Promjena aplikacije"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Sjajno!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Izvršili ste pokret za promjenu aplikacije."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Prikaži sve aplikacije"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipku za radnju na tipkovnici"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Izvrsno!"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index e914e755a934..cce273260779 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Frissítés…"</string> <string name="status_bar_work" msgid="5238641949837091056">"Munkahelyi profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Repülős üzemmód"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nem fogja hallani az ébresztést ekkor: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"ekkor: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ezen a napon: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Műhold, jó kapcsolat"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Műhold, van rendelkezésre álló kapcsolat"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Műholdas SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Csak segélyhívás vagy SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"nincs jel"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"egy sáv"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Vissza"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Értesítések"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Billentyűkódok"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Billentyűzetkiosztás váltása"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"vagy"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Keresőkifejezés törlése"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Billentyűparancsok"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Rendszeralkalmazások"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Osztott képernyő"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Bevitel"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Alkalmazásikonok"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Jelenlegi alkalmazás"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Gyorsparancsok személyre szabása"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Eltávolítja a billentyűparancsot?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Visszaállítja az alapértelmezett beállításokat?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Nyomja meg a billentyűt a billentyűparancs hozzárendeléséhez"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"A billentyűparancs létrehozásához nyomja le egyszerre a műveletbillentyűt és egy vagy több másik billentyűt"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Ezzel véglegesen törli az egyéni billentyűparancsot."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Ezzel véglegesen törli az összes egyéni billentyűparancsot."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Billentyűparancsok keresése"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Igen, visszaállítom"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Mégse"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Nyomja le a billentyűt"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"A billentyűkombináció már használatban van. Próbálkozzon másik billentyűvel."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"A billentyűkombináció már használatban van. Próbálkozzon másik kombinációval."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Nem lehet beállítani a billentyűparancsot."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Billentyűparancs hozzáadása"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Vissza"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ugrás a főoldalra"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Legutóbbi alkalmazások megtekintése"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Váltás az alkalmazások között"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Kész"</string> <string name="gesture_error_title" msgid="469064941635578511">"Próbálja újra"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Vissza"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Kiváló!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Teljesítette a legutóbbi alkalmazások megtekintésének kézmozdulatát."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"A legutóbbi appokért csúsztasson gyorsan három ujjal felfelé az érintőpadon, és tartsa lenyomva ujjait."</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Váltás az alkalmazások között"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Kiváló!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Teljesítette az appváltó gesztust."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Összes alkalmazás megtekintése"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Nyomja meg a műveletbillentyűt az érintőpadon."</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Szép munka!"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 262c3dd93cdd..10cf6703e3e0 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Թարմացում"</string> <string name="status_bar_work" msgid="5238641949837091056">"Android for Work-ի պրոֆիլ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Ավիառեժիմ"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ժամը <xliff:g id="WHEN">%1$s</xliff:g>-ի զարթուցիչը չի զանգի"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>-ին"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-ին"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Արբանյակային լավ կապ"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Հասանելի է արբանյակային կապ"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Միայն շտապ կանչեր կամ SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>։"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ազդանշան չկա"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"մեկ գիծ"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Հետ"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Ծանուցումներ"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Ստեղնային դյուրանցումներ"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Դասավորության փոխարկում"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"կամ"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Ջնջել որոնման հարցումը"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Ստեղնային դյուրանցումներ"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Համակարգային հավելվածներ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Բազմախնդրություն"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Տրոհված էկրան"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Ներածում"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Հավելվածի դյուրանցումներ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Այս հավելվածը"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Դյուրանցումների անհատականացում"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Հեռացնե՞լ դյուրանցումը"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Վերականգնե՞լ կանխադրվածները"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Սեղմեք որևէ ստեղն՝ դյուրանցում նշանակելու համար"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Այս դյուրանցումը ստեղծելու համար սեղմեք գործողության ստեղնը ու ևս մեկ կամ մի քանի ստեղներ"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Ձեր հատուկ դյուրանցումն ընդմիշտ կջնջվի։"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Բոլոր հատուկ դյուրանցումներն ընդմիշտ կջնջվեն։"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Դյուրանցումների որոնում"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Վերականգնել"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Չեղարկել"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Սեղմեք որևէ ստեղն"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ստեղների համակցությունն արդեն օգտագործվում է։ Ընտրեք ուրիշը։"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Ստեղների համակցությունն արդեն օգտագործվում է։ Ընտրեք ուրիշը։"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Դյուրանցումը հնարավոր չէ ստեղծել։"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Ավելացնել դյուրանցում"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Ինչպես հետ գնալ"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ինչպես անցնել հիմնական էկրան"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Դիտել վերջին հավելվածները"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Անցում մեկ հավելվածից մյուսին"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Պատրաստ է"</string> <string name="gesture_error_title" msgid="469064941635578511">"Նորից փորձեք։"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Հետ գնալ"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Կեցցե՛ք"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Դուք կատարեցիք վերջին օգտագործված հավելվածների դիտման ժեստը։"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Վերջին հավելվածները տեսնելու համար երեք մատը սահեցրեք վերև և սեղմած պահեք հպահարթակին"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Անցում մեկ հավելվածից մյուսին"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Կեցցե՛ք։"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Դուք սովորեցիք ուրիշ հավելված անցնելու ժեստը։"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ինչպես դիտել բոլոր հավելվածները"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Սեղմեք գործողության ստեղնը ստեղնաշարի վրա"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Հիանալի՛ է"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 8e1118c76e24..a5f01997654a 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Update berlangsung"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode pesawat"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar alarm berikutnya <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"pukul <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"pada <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, koneksi baik"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, koneksi tersedia"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via Satelit"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Panggilan darurat atau SOS saja"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"tidak ada sinyal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"satu batang"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Kembali"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notifikasi"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Pintasan keyboard"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Ganti tata letak keyboard"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"atau"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Hapus kueri penelusuran"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Pintasan Keyboard"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplikasi sistem"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Layar terpisah"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Pintasan aplikasi"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplikasi Saat Ini"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Sesuaikan pintasan"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Hapus pintasan?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Reset kembali ke pintasan default?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tekan tombol untuk menetapkan pintasan"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Untuk membuat pintasan ini, tekan tombol Tindakan dan satu atau beberapa tombol lainnya secara bersamaan"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Tindakan ini akan menghapus pintasan kustom Anda secara permanen."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Tindakan ini akan menghapus semua pintasan kustom Anda secara permanen."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Telusuri pintasan"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ya, reset"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Batal"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tekan tombol"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinasi tombol sudah digunakan. Coba tombol lain."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Kombinasi tombol sudah digunakan. Coba kombinasi lain."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Pintasan tidak dapat disetel."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Tambahkan pintasan"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Kembali"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Buka layar utama"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Lihat aplikasi terbaru"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Beralih aplikasi"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Selesai"</string> <string name="gesture_error_title" msgid="469064941635578511">"Coba lagi"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bagus!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda telah menyelesaikan gestur untuk melihat aplikasi terbaru."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Untuk melihat aplikasi terbaru, geser ke atas dan tahan menggunakan tiga jari di touchpad"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Beralih aplikasi"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bagus!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Anda telah menyelesaikan gestur beralih aplikasi."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Lihat semua aplikasi"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tekan tombol tindakan di keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Oke!"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index f5488e0939de..576a22742573 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Uppfærir"</string> <string name="status_bar_work" msgid="5238641949837091056">"Vinnusnið"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flugstilling"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ekki mun heyrast í vekjaranum <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Gervihnöttur, góð tenging"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Gervihnöttur, tenging tiltæk"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Gervihnattar-SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Neyðarsímtöl eða SOS eingöngu"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ekkert samband"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"eitt strik"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Til baka"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Tilkynningar"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Flýtilyklar"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Skipta um lyklaskipan"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"eða"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Hreinsa leitarfyrirspurn"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Flýtilyklar"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Kerfisforrit"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Fjölvinnsla"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Skjáskipting"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Innsláttur"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Flýtileiðir forrita"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Núverandi forrit"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Sérsníða flýtilykla"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Fjarlægja flýtileið?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Endurstilla á sjálfgefið?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Ýttu á lykil til að stilla flýtileið"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Til að búa til þessa flýtileið skaltu ýta á aðgerðalykilinn og einn eða fleiri lykla saman"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Þetta eyðir sérsniðnu flýtileiðinni varanlega."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Þetta verður til þess að öllum sérsniðnu flýtileiðunum þínum verður eytt varanlega."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Leita að flýtileiðum"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Já, endurstilla"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Hætta við"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Ýttu á lykil"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Lyklasamsetningin er þegar í notkun. Prófaðu annan lykil."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Lyklasamsetningin er þegar í notkun. Prófaðu aðra samsetningu."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Ekki er hægt að stilla flýtileið."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Bæta flýtileið við"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Til baka"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Fara á heimaskjá"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Sjá nýleg forrit"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Að skipta á milli forrita"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Lokið"</string> <string name="gesture_error_title" msgid="469064941635578511">"Reyndu aftur!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Til baka"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Vel gert!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Þú framkvæmdir bendinguna til að sjá nýleg forrit."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Strjúktu upp og haltu þremur fingrum inni á snertifletinum til að sjá nýleg forrit"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Að skipta á milli forrita"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Vel gert!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Þú framkvæmdir bendinguna til að skipta á milli forrita."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Sjá öll forrit"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Ýttu á aðgerðalykilinn á lyklaborðinu"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Vel gert!"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 81367f369159..9b847c4c344d 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Aggiornamento in corso…"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profilo di lavoro"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modalità aereo"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Non sentirai la tua prossima sveglia <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"alle <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellitare, connessione buona"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellitare, connessione disponibile"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS satellitare"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Solo chiamate di emergenza o SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"nessun segnale"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"una barra"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Indietro"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notifiche"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Scorciatoie da tastiera"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Cambia layout della tastiera"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"o"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Cancella la query di ricerca"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Scorciatoie da tastiera"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"App di sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Schermo diviso"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Scorciatoie app"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App corrente"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizza scorciatoie"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Rimuovere scorciatoia?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vuoi ripristinare le impostazioni predefinite?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Premi un tasto per assegnare una scorciatoia"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Per creare questa scorciatoia, premi il tasto Azione e uno o più altri tasti contemporaneamente"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"La scorciatoia personalizzata verrà eliminata definitivamente."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Tutte le tue scorciatoie personalizzate verranno eliminate definitivamente."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Cerca scorciatoie"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sì, ripristina"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annulla"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Premi un tasto"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Combinazione di tasti già in uso. Prova con un altro tasto."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Combinazione di tasti già in uso. Prova un\'altra combinazione."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Impossibile impostare la scorciatoia."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Aggiungi scorciatoia"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Indietro"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Vai alla schermata Home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Visualizza app recenti"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Cambia app"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fine"</string> <string name="gesture_error_title" msgid="469064941635578511">"Riprova."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Indietro"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Ottimo lavoro!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Hai completato il gesto Visualizza app recenti."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Per visualizzare le app recenti, scorri verso l\'alto e tieni premuto con tre dita sul touchpad"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Cambia app"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Ottimo lavoro."</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Hai completato il gesto Cambia app."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Visualizza tutte le app"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Premi il tasto azione sulla tastiera"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Ben fatto!"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index a40dd62c4620..afa1af584c44 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"מתבצע עדכון"</string> <string name="status_bar_work" msgid="5238641949837091056">"פרופיל עבודה"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"מצב טיסה"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"לא ניתן יהיה לשמוע את השעון המעורר הבא שלך <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"בשעה <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ב-<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"לוויין, חיבור באיכות טובה"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"לוויין, יש חיבור זמין"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"תקשורת לוויינית למצב חירום"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"רק שיחות חירום או תקשורת לוויינית למצב חירום"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"אין קליטה"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"פס אחד"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"חזרה"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"התראות"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"מקשי קיצור במקלדת"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"החלפה של פריסת מקלדת"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"או"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ניקוי שאילתת החיפוש"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"מקשי קיצור"</string> @@ -1432,16 +1432,17 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"אפליקציות מערכת"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ריבוי משימות"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"מסך מפוצל"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"קלט"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"מקשי קיצור לאפליקציות"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"האפליקציה הנוכחית"</string> <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"נגישות"</string> <string name="shortcut_helper_title" msgid="8567500639300970049">"מקשי קיצור"</string> - <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) --> - <skip /> + <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"התאמה אישית של מקשי הקיצור"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"להסיר את קיצור הדרך?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"לאפס לברירת המחדל?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"צריך להקיש על מקש כדי להקצות מקש קיצור"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"כדי ליצור את קיצור הדרך הזה, מקישים על מקש הפעולה ועל עוד מקש אחד או יותר ביחד"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"קיצור הדרך יימחק לתמיד."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"הפעולה הזו תמחק לתמיד את כל קיצורי הדרך שמותאמים אישית."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"חיפוש מקשי קיצור"</string> @@ -1463,13 +1464,11 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"כן, לאפס"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ביטול"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"יש ללחוץ על מקש"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"שילוב המקשים הזה כבר בשימוש. אפשר לנסות מקש אחר."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"שילוב המקשים הזה תפוס. צריך לנסות שילוב אחר."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"לא ניתן להגדיר את קיצור הדרך."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> - <!-- no translation found for shortcut_helper_add_shortcut_button_label (7655779534665954910) --> - <skip /> - <!-- no translation found for shortcut_helper_delete_shortcut_button_label (3148773472696137052) --> - <skip /> + <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"הוספת קיצור דרך"</string> + <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"מחיקת קיצור הדרך"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ניווט באמצעות המקלדת"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"מידע על מקשי קיצור"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ניווט באמצעות לוח המגע"</string> @@ -1479,6 +1478,8 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"חזרה"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"חזרה לדף הבית"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"הצגת האפליקציות האחרונות"</string> + <!-- no translation found for touchpad_tutorial_switch_apps_gesture_button (7768255095423767779) --> + <skip /> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"סיום"</string> <string name="gesture_error_title" msgid="469064941635578511">"צריך לנסות שוב."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"חזרה"</string> @@ -1496,6 +1497,16 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"מעולה!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"סיימת לתרגל את התנועה להצגת האפליקציות האחרונות."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"כדי לראות את האפליקציות האחרונות, צריך להחליק למעלה וללחוץ לחיצה ארוכה עם שלוש אצבעות על לוח המגע"</string> + <!-- no translation found for touchpad_switch_apps_gesture_action_title (6835222344612924512) --> + <skip /> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <!-- no translation found for touchpad_switch_apps_gesture_success_title (4894947244328032458) --> + <skip /> + <!-- no translation found for touchpad_switch_apps_gesture_success_body (8151089866035126312) --> + <skip /> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"צפייה בכל האפליקציות"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"צריך להקיש על מקש הפעולה במקלדת"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"כל הכבוד!"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 8941217e8cbd..87c6aedfd4a0 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"更新しています"</string> <string name="status_bar_work" msgid="5238641949837091056">"仕事用プロファイル"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"機内モード"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"次回のアラーム(<xliff:g id="WHEN">%1$s</xliff:g>)は鳴りません"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"衛生、接続状態良好"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"衛生、接続利用可能"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"衛星 SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"緊急通報または SOS のみ"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>、<xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>。"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"圏外"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"レベル 1"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"戻る"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"通知"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"キーボード ショートカット"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"キーボード レイアウトの切り替え"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"または"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"検索クエリをクリア"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"キーボード ショートカット"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"システムアプリ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"マルチタスク"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"分割画面"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"入力"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"アプリのショートカット"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"現在のアプリ"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ショートカットのカスタマイズ"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ショートカットを削除しますか?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"デフォルトにリセットしますか?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ショートカットを割り当てるキーを押してください"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"このショートカットを作成するには、アクションキーと他のキー(複数可)を同時に押してください"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"この操作を行うと、カスタム ショートカットが完全に削除されます。"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"この操作を行うと、すべてのカスタム ショートカットが完全に削除されます。"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ショートカットの検索"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"リセット"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"キャンセル"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"キーを押してください"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"このキーの組み合わせはすでに使用されています。別のキーを試してください。"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"このキーの組み合わせはすでに使用されています。別の組み合わせをお試しください。"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ショートカットを設定できません。"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ショートカットを追加"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"戻る"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ホームに移動"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"最近使ったアプリを表示する"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"アプリの切り替え"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完了"</string> <string name="gesture_error_title" msgid="469064941635578511">"もう一度お試しください。"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"戻る"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"よくできました!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"「最近使ったアプリを表示する」ジェスチャーを学習しました。"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"最近使ったアプリを表示するには、3 本の指でタッチパッドを上にスワイプして長押しします"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"アプリの切り替え"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"よくできました!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"アプリを切り替えるジェスチャーを学習しました。"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"すべてのアプリを表示"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"キーボードのアクションキーを押します"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"完了です!"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 6937048c1826..31f486f05373 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"მიმდინარეობს განახლება"</string> <string name="status_bar_work" msgid="5238641949837091056">"სამსახურის პროფილი"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"თვითმფრინავის რეჟიმი"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"ვერ გაიგონებთ მომდევნო მაღვიძარას <xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"კარგი სატელიტური კავშირი"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ხელმისაწვდომია სატელიტური კავშირი"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"სატელიტური SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"გადაუდებელი ზარი ან მხოლოდ SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"სიგნალი არ არის"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"ერთი ხაზი"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"უკან"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"შეტყობინებები"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"კლავიატურის მალსახმობები"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"კლავიატურის განლაგების გადართვა"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ან"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"საძიებო ფრაზის გასუფთავება"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"კლავიატურის მალსახმობები"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"სისტემის აპები"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"მრავალამოცანიანი რეჟიმი"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"ეკრანის გაყოფა"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"შეყვანა"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"აპის მალსახმობები"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"მიმდინარე აპი"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"მალსახმობების მორგება"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"გსურთ მალსახმობის წაშლა?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"გსურთ ნაგულისხმევზე გადაყენება?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"მალსახმობის მინიჭებისთვის დააჭირეთ კლავიშს"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"ამ მალსახმობის შესაქმნელად ერთად დააჭირეთ მოქმედების კლავიშს და ერთ ან მეტ სხვა კლავიშს"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ეს თქვენს მორგებულ მალსახმობებს სამუდამოდ წაშლის."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ეს სამუდამოდ წაშლის თქვენს ყველა მორგებულ მალსახმობს."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ძიების მალსახმობები"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"დიახ, გადაყენდეს"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"გაუქმება"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"დააჭირეთ კლავიშს"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"კლავიშების კომბინაცია უკვე გამოიყენება. ცადეთ სხვა კლავიში."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"კლავიშების კომბინაცია უკვე გამოიყენება. ცადეთ სხვა კომბინაცია."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"მალსახმობის დაყენება ვერ ხერხდება."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"მალსახმობის დამატება"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"უკან დაბრუნება"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"მთავარ ეკრანზე გადასვლა"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ბოლო აპების ნახვა"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"აპების გადართვა"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"მზადაა"</string> <string name="gesture_error_title" msgid="469064941635578511">"ცადეთ ხელახლა!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"უკან დაბრუნება"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"შესანიშნავია!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"თქვენ დაასრულეთ ბოლო აპების ხედის ჟესტი."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ბოლო აპების სანახავად თქვენს სენსორულ პანელზე სამი თითით გადაფურცლეთ ზევით და ხანგრძლივად დააჭირეთ"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"აპების გადართვა"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"შესანიშნავია!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"თქვენ შეასრულეთ აპების გადართვის ჟესტი."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ყველა აპის ნახვა"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"დააჭირეთ მოქმედების კლავიშს თქვენს კლავიატურაზე"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ყოჩაღ!"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index d6f0a006f588..0b6c7b9919b2 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Жаңартылып жатыр"</string> <string name="status_bar_work" msgid="5238641949837091056">"Жұмыс профилі"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Ұшақ режимі"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Келесі <xliff:g id="WHEN">%1$s</xliff:g> дабылыңызды есітпейсіз"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Жерсерік, байланыс жақсы."</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Жерсерік, байланыс бар."</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Тек құтқару қызметіне қоңырау шалу немесе SOS сигналын жіберу"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"сигнал жоқ"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"бір жолақ"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Артқа"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Хабарландырулар"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Перне тіркесімдері"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Пернетақта форматын ауыстыру"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"немесе"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Іздеу сұрауын өшіру"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Перне тіркесімдері"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Жүйелік қолданбалар"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Мультитаскинг"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Экранды бөлу"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Енгізу"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Қолданба таңбашалары"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Қолданыстағы қолданба"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Пернелер тіркесімін бейімдеу"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Тіркесімді өшіру керек пе?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Әдепкі тіркесімге қайтару керек пе?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Тіркесім тағайындау үшін пернені басыңыз."</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Осы тіркесімді жасау үшін әрекет пернесін және басқа бір не бірнеше пернені бірге басыңыз."</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Арнаулы тіркесіміңіз біржола жойылады."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Мұндайда барлық арнаулы тіркесім біржола жойылады."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Тіркесімдерді іздеу"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Иә, қайтару"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Бас тарту"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Пернені басыңыз"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Бұл пернелер тіркесімі қазір қолданыста. Басқа перне таңдаңыз."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Бұл пернелер тіркесімі бұрыннан қолданылады. Басқа тіркесімді пайдаланып көріңіз."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Перне тіркесімін орнату мүмкін емес."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Жылдам пәрмен қосу"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Артқа"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Негізгі бетке өту"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Соңғы қолданбаларды көру"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Қолданба ауыстыру"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Дайын"</string> <string name="gesture_error_title" msgid="469064941635578511">"Қайталап көріңіз"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Артқа"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Жарайсыз!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Соңғы қолданбаларды көру қимылын орындадыңыз."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Соңғы қолданбаларды көру үшін сенсорлық тақтада үш саусақпен жоғары сырғытып, ұстап тұрыңыз."</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Қолданба ауыстыру"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Жарайсыз!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Қолданба ауыстыру қимылын аяқтадыңыз."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Барлық қолданбаны көру"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Пернетақтадағы әрекет пернесін басыңыз."</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Жарайсыз!"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index efbc0aa0d68c..a2f5b01c81de 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"កំពុងដំឡើងកំណែ"</string> <string name="status_bar_work" msgid="5238641949837091056">"កម្រងព័ត៌មានការងារ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ពេលជិះយន្តហោះ"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"អ្នកនឹងមិនលឺម៉ោងរោទ៍ <xliff:g id="WHEN">%1$s</xliff:g> បន្ទាប់របស់អ្នកទេ"</string> <string name="alarm_template" msgid="2234991538018805736">"នៅ <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"នៅ <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ផ្កាយរណប មានការតភ្ជាប់ល្អ"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ផ្កាយរណប អាចតភ្ជាប់បាន"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ការប្រកាសអាសន្នតាមផ្កាយរណប"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"សម្រាប់ការហៅទៅលេខសង្គ្រោះបន្ទាន់ ឬការប្រកាសអាសន្នតែប៉ុណ្ណោះ"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>។"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"គ្មានសញ្ញា"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"មួយកាំ"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"ថយក្រោយ"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"ការជូនដំណឹង"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"ផ្លូវកាត់ក្ដារចុច"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"ប្ដូរប្លង់ក្ដារចុច"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ឬ"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"សម្អាតសំណួរស្វែងរក"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"ផ្លូវកាត់ក្ដារចុច"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"កម្មវិធីប្រព័ន្ធ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ការធ្វើកិច្ចការច្រើន"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"មុខងារបំបែកអេក្រង់"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"វិធីបញ្ចូល"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ផ្លូវកាត់កម្មវិធី"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"កម្មវិធីបច្ចុប្បន្ន"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ប្ដូរផ្លូវកាត់តាមបំណង"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ដកផ្លូវកាត់ចេញឬ?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"កំណត់ឡើងវិញទៅលំនាំដើមឬ?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ចុចគ្រាប់ចុច ដើម្បីកំណត់ផ្លូវកាត់"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"ដើម្បីបង្កើតផ្លូវកាត់នេះ សូមចុចគ្រាប់ចុចសកម្មភាព និងគ្រាប់ចុចមួយ ឬច្រើនផ្សេងទៀតជាមួយគ្នា"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ការធ្វើបែបនេះនឹងលុបផ្លូវកាត់ផ្ទាល់ខ្លួនរបស់អ្នកជាអចិន្ត្រៃយ៍។"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"សកម្មភាពនេះនឹងលុបផ្លូវកាត់ផ្ទាល់ខ្លួនរបស់អ្នកទាំងអស់ជាអចិន្ត្រៃយ៍។"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ស្វែងរកផ្លូវកាត់"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"បាទ/ចាស កំណត់ឡើងវិញ"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"បោះបង់"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ចុចគ្រាប់ចុច"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"បន្សំគ្រាប់ចុចនេះត្រូវបានប្រើប្រាស់ហើយ។ សាកល្បងគ្រាប់ចុចផ្សេង។"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"កំពុងប្រើបន្សំគ្រាប់ចុចស្រាប់ហើយ។ សូមសាកល្បងបន្សំគ្រាប់ចុចផ្សេង។"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"មិនអាចកំណត់ផ្លូវកាត់បានទេ។"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"បញ្ចូលផ្លូវកាត់"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ថយក្រោយ"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ទៅទំព័រដើម"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"មើលកម្មវិធីថ្មីៗ"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"ប្ដូរកម្មវិធី"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"រួចរាល់"</string> <string name="gesture_error_title" msgid="469064941635578511">"សូមព្យាយាមម្ដងទៀត!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ថយក្រោយ"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ធ្វើបានល្អ!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"អ្នកបានបញ្ចប់ការមើលចលនាកម្មវិធីថ្មីៗ។"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ដើម្បីមើលកម្មវិធីថ្មីៗ សូមអូសឡើងលើ រួចសង្កត់ឱ្យជាប់លើផ្ទាំងប៉ះរបស់អ្នក ដោយប្រើម្រាមដៃបី"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ប្ដូរកម្មវិធី"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ធ្វើបានល្អ!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"អ្នកបានបញ្ចប់ចលនាប្ដូរកម្មវិធីហើយ។"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"មើលកម្មវិធីទាំងអស់"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ចុចគ្រាប់ចុចសកម្មភាពលើក្ដារចុចរបស់អ្នក"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ធ្វើបានល្អ!"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index ded267feee65..76f38c0337db 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"ಅಪ್ಡೇಟ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string> <string name="status_bar_work" msgid="5238641949837091056">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ಏರ್ಪ್ಲೇನ್ ಮೋಡ್"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"ನಿಮ್ಮ ಮುಂದಿನ <xliff:g id="WHEN">%1$s</xliff:g> ಅಲಾರಮ್ ಅನ್ನು ನೀವು ಆಲಿಸುವುದಿಲ್ಲ"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ರಲ್ಲಿ"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ರಂದು"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ಸ್ಯಾಟಲೈಟ್, ಕನೆಕ್ಷನ್ ಉತ್ತಮವಾಗಿದೆ"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ಸ್ಯಾಟಲೈಟ್, ಕನೆಕ್ಷನ್ ಲಭ್ಯವಿದೆ"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ಸ್ಯಾಟಲೈಟ್ SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"ತುರ್ತು ಕರೆಗಳು ಅಥವಾ SOS ಮಾತ್ರ"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ಸಿಗ್ನಲ್ ಇಲ್ಲ"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"ಒಂದು ಬಾರ್"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"ಹಿಂದೆ"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"ನೋಟಿಫಿಕೇಶನ್ಗಳು"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಬದಲಾಯಿಸಿ"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ಅಥವಾ"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ಹುಡುಕಾಟದ ಪ್ರಶ್ನೆಯನ್ನು ತೆರವುಗೊಳಿಸಿ"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"ಸಿಸ್ಟಂ ಆ್ಯಪ್ಗಳು"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ಮಲ್ಟಿಟಾಸ್ಕಿಂಗ್"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ಇನ್ಪುಟ್"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ಆ್ಯಪ್ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ಪ್ರಸ್ತುತ ಆ್ಯಪ್"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ತೆಗೆದುಹಾಕಬೇಕೇ?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ಡೀಫಾಲ್ಟ್ಗೆ ರೀಸೆಟ್ ಮಾಡಬೇಕೆ?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ನಿಯೋಜಿಸಲು ಕೀಯನ್ನು ಒತ್ತಿರಿ"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"ಈ ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ರಚಿಸಲು, ಆಕ್ಷನ್ ಕೀ ಮತ್ತು ಒಂದು ಅಥವಾ ಹೆಚ್ಚಿನ ಇತರ ಕೀಗಳನ್ನು ಒಟ್ಟಿಗೆ ಒತ್ತಿರಿ"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ಇದು ನಿಮ್ಮ ಕಸ್ಟಮ್ ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಶಾಶ್ವತವಾಗಿ ಅಳಿಸುತ್ತದೆ."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ಇದು ನಿಮ್ಮ ಎಲ್ಲಾ ಕಸ್ಟಮ್ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಶಾಶ್ವತವಾಗಿ ಅಳಿಸುತ್ತದೆ."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ಹುಡುಕಾಟದ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ಹೌದು, ರೀಸೆಟ್ ಮಾಡಿ"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ರದ್ದುಮಾಡಿ"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ಕೀ ಅನ್ನು ಒತ್ತಿರಿ"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"ಕೀ ಸಂಯೋಜನೆಯು ಈಗಾಗಲೇ ಬಳಕೆಯಲ್ಲಿದೆ. ಮತ್ತೊಂದು ಕೀ ಬಳಸಿ ನೋಡಿ."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"ಕೀ ಸಂಯೋಜನೆಯು ಈಗಾಗಲೇ ಬಳಕೆಯಲ್ಲಿದೆ. ಮತ್ತೊಂದು ಸಂಯೋಜನೆಯನ್ನು ನೋಡಿ."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಸೆಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ಶಾರ್ಟ್ಕಟ್ ಸೇರಿಸಿ"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ಹಿಂದಿರುಗಿ"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ಮುಖಪುಟಕ್ಕೆ ಹೋಗಿ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಿಸಿ"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ಮುಗಿದಿದೆ"</string> <string name="gesture_error_title" msgid="469064941635578511">"ಪುನಃ ಪ್ರಯತ್ನಿಸಿ!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ಹಿಂತಿರುಗಿ"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ಭೇಷ್!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ನೀವು ಇತ್ತೀಚಿನ ಆ್ಯಪ್ಗಳ ಜೆಸ್ಚರ್ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು, ನಿಮ್ಮ ಟಚ್ಪ್ಯಾಡ್ನಲ್ಲಿ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಿಸಿ"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ಭೇಷ್!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ನೀವು ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸುವ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ನಲ್ಲಿ ಆ್ಯಕ್ಷನ್ ಕೀಯನ್ನು ಒತ್ತಿ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ಭೇಷ್!"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 732c9bc8620c..c087e5891229 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"업데이트 중"</string> <string name="status_bar_work" msgid="5238641949837091056">"직장 프로필"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"비행기 모드"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>에 다음 알람을 들을 수 없습니다."</string> <string name="alarm_template" msgid="2234991538018805736">"시간: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"일시: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"위성, 연결 상태 양호"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"위성, 연결 가능"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"위성 긴급 SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"긴급 전화 또는 SOS만 허용"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"신호가 없습니다"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"신호 막대가 1개입니다"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"뒤로"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"알림"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"단축키"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"키보드 레이아웃 전환"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"또는"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"검색어 삭제"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"단축키"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"시스템 앱"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"멀티태스킹"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"화면 분할"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"입력"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"앱 단축키"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"현재 앱"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"단축키 맞춤설정"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"단축키를 삭제하시겠어요?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"기본값으로 재설정하시겠어요?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"키를 눌러 단축키 지정"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"이 단축키를 만들려면 작업 키와 다른 키 하나 이상을 함께 누르세요"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"맞춤 단축키가 영구적으로 삭제됩니다."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"모든 맞춤 단축키가 완전히 삭제됩니다."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"단축키 검색"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"재설정"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"취소"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"키를 누르세요."</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"이미 사용 중인 키 조합입니다. 다른 키를 사용해 보세요."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"이미 사용 중인 키 조합입니다. 다른 조합을 사용해 보세요."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"단축키를 설정할 수 없습니다."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"단축키 추가"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"뒤로 이동"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"홈으로 이동"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"최근 앱 보기"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"앱 전환"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"완료"</string> <string name="gesture_error_title" msgid="469064941635578511">"다시 시도해 보세요"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"뒤로"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"아주 좋습니다"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"최근 앱 보기 동작을 완료했습니다."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"최근 앱을 보려면 터치패드에서 세 손가락을 사용해 위로 스와이프한 채로 유지하세요."</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"앱 전환"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"잘하셨습니다"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"앱 전환 동작을 완료했습니다."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"모든 앱 보기"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"키보드의 작업 키를 누르세요."</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"잘하셨습니다"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index eb5960fa23cd..5d1b604fa152 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Жаңырууда"</string> <string name="status_bar_work" msgid="5238641949837091056">"Жумуш профили"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Учак режими"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> боло турган кийинки эскертмени укпайсыз"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> болгондо"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> болгондо"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Спутник, байланыш жакшы"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Спутник, байланыш бар"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Спутник SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Шашылыш чалуулар же SOS гана"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"сигнал жок"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"бир мамыча"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Артка"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Билдирмелер"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Ыкчам баскычтар"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Баскычтоп калыбын которуштуруу"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"же"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Изделген суроону тазалоо"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Ыкчам баскычтар"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системанын колдонмолору"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Бир нече тапшырма аткаруу"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Экранды бөлүү"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Киргизүү"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Колдонмонун ыкчам баскычтары"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Учурдагы колдонмо"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Ыкчам баскычтарды тууралоо"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Ыкчам баскыч өчүрүлсүнбү?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Баштапкы абалга келтиресизби?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Ыкчам баскычты дайындоо үчүн баскычты басыңыз"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Бул ыкчам баскычты түзүү үчүн Аракет баскычын жана бир же бир нече башка баскычты чогуу басыңыз"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Ушуну менен жеке ыкчам баскычыңыз биротоло өчүрүлөт."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Ушуну менен жеке ыкчам баскычтарыңыздын баары биротоло өчүрүлөт."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Ыкчам баскычтарды издөө"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ооба, баштапкы абалга келтирилсин"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Баскычты басыңыз"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ачкычтардын айкалышы колдонулууда. Башка ачкычты байкап көрүңүз."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Ачкычтардын айкалышы колдонулууда. Башка айкалышты колдонуп көрүңүз."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Ыкчам баскычты коюу мүмкүн эмес."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Ыкчам баскыч кошуу"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Артка кайтуу"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Башкы бетке өтүү"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Акыркы колдонмолорду көрүү"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Колдонмолорду которуштуруу"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Бүттү"</string> <string name="gesture_error_title" msgid="469064941635578511">"Кайталап көрүңүз!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Артка кайтуу"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Азаматсыз!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Акыркы колдонмолорду көрүү жаңсоосун аткардыңыз."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Соңку колдонмолорду көрүү үчүн сенсордук тактаны үч манжаңыз менен жогору сүрүп, кармап туруңуз"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Колдонмолорду которуштуруу"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Азаматсыз!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"\"Башка колдонмого которулуу жаңсоосу боюнча үйрөткүчтү бүтүрдүңүз."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Бардык колдонмолорду көрүү"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Баскычтобуңуздагы аракет баскычын басыңыз"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Эң жакшы!"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 19ddc7aa5c9a..37713b32ac9d 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"ກຳລັງອັບເດດ"</string> <string name="status_bar_work" msgid="5238641949837091056">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ໂໝດຢູ່ໃນຍົນ"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"ທ່ານຈະບໍ່ໄດ້ຍິນສຽງໂມງປ <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"ເວລາ <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ວັນ <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ດາວທຽມ, ການເຊື່ອມຕໍ່ດີ"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ດາວທຽມ, ການເຊື່ອມຕໍ່ທີ່ພ້ອມນຳໃຊ້"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS ດາວທຽມ"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"ໂທສຸກເສີນ ຫຼື SOS ເທົ່ານັ້ນ"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ບໍ່ມີສັນຍານ"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"1 ຂີດ"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"ກັບຄືນ"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"ການແຈ້ງເຕືອນ"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"ປຸ່ມລັດແປ້ນພິມ"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"ສະຫຼັບແປ້ນພິມ"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ຫຼື"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ລຶບລ້າງຄຳຊອກຫາ"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"ຄີລັດ"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"ແອັບລະບົບ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ການເຮັດຫຼາຍໜ້າວຽກພ້ອມກັນ"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"ແບ່ງໜ້າຈໍ"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ອິນພຸດ"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ທາງລັດແອັບ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ແອັບປັດຈຸບັນ"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ປັບແຕ່ງທາງລັດ"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ລຶບທາງລັດອອກບໍ?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ຣີເຊັດກັບຄືນເປັນຄ່າເລີ່ມຕົ້ນບໍ?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ກົດປຸ່ມເພື່ອກຳນົດທາງລັດ"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"ເພື່ອສ້າງທາງລັດນີ້, ໃຫ້ກົດປຸ່ມຄຳສັ່ງ ແລະ ໜຶ່ງ ຫຼື ຫຼາຍປຸ່ມອື່ນໆຮ່ວມກັນ"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ການດຳເນີນການນີ້ຈະລຶບທາງລັດທີ່ກຳນົດເອງຂອງທ່ານຢ່າງຖາວອນ."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ການດຳເນີນການນີ້ຈະລຶບທາງລັດທີ່ກຳນົດເອງທັງໝົດຂອງທ່ານຢ່າງຖາວອນ."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ທາງລັດການຊອກຫາ"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ແມ່ນ, ຣີເຊັດ"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ຍົກເລີກ"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ກົດປຸ່ມ"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"ນໍາໃຊ້ປຸ່ມປະສົມຢູ່ແລ້ວ. ໃຫ້ລອງປຸ່ມອື່ນ."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"ນໍາໃຊ້ປຸ່ມປະສົມຢູ່ແລ້ວ. ລອງໃຊ້ການປະສົມປະສານອື່ນໆ."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ຕັ້ງທາງລັດບໍ່ໄດ້."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ເພີ່ມທາງລັດ"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ກັບຄືນ"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ໄປຫາໜ້າຫຼັກ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ເບິ່ງແອັບຫຼ້າສຸດ"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"ສະຫຼັບແອັບ"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ແລ້ວໆ"</string> <string name="gesture_error_title" msgid="469064941635578511">"ກະລຸນາລອງໃໝ່!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ກັບຄືນ"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ດີຫຼາຍ!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ທ່ານເບິ່ງທ່າທາງຂອງແອັບຫຼ້າສຸດສຳເລັດແລ້ວ."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ເພື່ອເບິ່ງແອັບຫຼ້າສຸດ, ໃຫ້ປັດຂຶ້ນແລ້ວຄ້າງໄວ້ໂດຍໃຊ້ສາມນິ້ວເທິງແຜ່ນສຳຜັດຂອງທ່ານ"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ສະຫຼັບແອັບ"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ດີຫຼາຍ!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ທ່ານເຮັດທ່າທາງສະຫຼັບແອັບສຳເລັດແລ້ວ."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ເບິ່ງແອັບທັງໝົດ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ກົດປຸ່ມຄຳສັ່ງຢູ່ແປ້ນພິມຂອງທ່ານ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ດີຫຼາຍ!"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 71ce30db0a02..4292574de55e 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Atnaujinama"</string> <string name="status_bar_work" msgid="5238641949837091056">"Darbo profilis"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lėktuvo režimas"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Negirdėsite kito signalo <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Palydovas, geras ryšys"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Palydovas, pasiekiamas ryšys"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Prisijungimas prie palydovo kritiniu atveju"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Tik skambučiai pagalbos numeriu arba prisijungimas prie palydovo kritiniu atveju"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"„<xliff:g id="CARRIER_NAME">%1$s</xliff:g>“, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"nėra signalo"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"viena juosta"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Atgal"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Pranešimai"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Spartieji klavišai"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Perjungti klaviat. išdėstymą"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"arba"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Išvalyti paieškos užklausą"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Spartieji klavišai"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistemos programos"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Kelių užduočių atlikimas"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Išskaidyto ekrano režimas"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Įvestis"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Programos spartieji klavišai"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Esama programa"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Sparčiųjų klavišų tinkinimas"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Pašalinti spartųjį klavišą?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Iš naujo nustatyti numatytąjį nustatymą?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Paspauskite klavišą, kad priskirtumėte spartųjį klavišą"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Jei norite sukurti šį spartųjį klavišą, paspauskite veiksmų klavišą ir vieną ar daugiau kitų klavišų"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Bus visam laikui ištrintas tinkintas spartusis klavišas."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Bus visam laikui ištrinti visi tinkinti šaukiniai."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Ieškoti sparčiųjų klavišų"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Taip, nustatyti iš naujo"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Atšaukti"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Paspauskite klavišą"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Klavišų derinys jau naudojamas. Bandykite naudoti kitą klavišą."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Klavišų derinys jau naudojamas. Bandykite naudoti kitą derinį."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Sparčiojo klavišo nustatyti negalima."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Pridėti spartųjį klavišą"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Grįžti"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Eikite į pagrindinį puslapį"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Peržiūrėti naujausias programas"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Perjungti programas"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Atlikta"</string> <string name="gesture_error_title" msgid="469064941635578511">"Bandykite dar kartą!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Grįžti"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Puiku!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Atlikote naujausių programų peržiūros gestą."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Peržiūrėkite naujausias programas, jutiklinėje dalyje perbraukę aukštyn trimis pirštais ir palaikę"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Perjungti programas"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Puiku!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Atlikote programų perjungimo gestą."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Žr. visas programas"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Paspauskite klaviatūros veiksmų klavišą"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Puikiai padirbėta!"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 271c081ea3a9..cac42758f8bf 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Notiek atjaunināšana"</string> <string name="status_bar_work" msgid="5238641949837091056">"Darba profils"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lidojuma režīms"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nākamais signāls (<xliff:g id="WHEN">%1$s</xliff:g>) netiks atskaņots."</string> <string name="alarm_template" msgid="2234991538018805736">"plkst. <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelīts, labs savienojums"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelīts, ir pieejams savienojums"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelīta SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Tikai ārkārtas izsaukumi vai SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"nav signāla"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"viena josla"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Atpakaļ"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Paziņojumi"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Īsinājumtaustiņi"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Mainīt tastatūras izkārtojumu"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"vai"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Notīrīt meklēšanas vaicājumu"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Īsinājumtaustiņi"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistēmas lietotnes"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Vairākuzdevumu režīms"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ekrāna sadalīšana"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Ievade"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Lietotņu saīsnes"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Pašreizējā lietotne"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Īsinājumtaustiņu pielāgošana"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Vai noņemt saīsni?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vai atiestatīt noklusējuma vērtības?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Lai piešķirtu īsinājumtaustiņu, nospiediet taustiņu"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Lai izveidotu šo īsinājumtaustiņu, vienlaikus nospiediet darbību taustiņu un vienu vai vairākus citus taustiņus"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Veicot šo darbību, jūsu pielāgotā saīsne tiks neatgriezeniski izdzēsta."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Veicot šo darbību, visas jūsu pielāgotās saīsnes tiks neatgriezeniski dzēstas."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Meklēt saīsnes"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Jā, atiestatīt"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Atcelt"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Nospiediet taustiņu"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Taustiņu kombinācija jau tiek izmantota. Izmēģiniet citu taustiņu."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Taustiņu kombinācija jau tiek izmantota. Izmēģiniet citu kombināciju."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Nevar iestatīt saīsni."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Pievienot saīsni"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Atpakaļ"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Pāriet uz sākuma ekrānu"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Skatīt nesen izmantotās lietotnes"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Pārslēgties starp lietotnēm"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gatavs"</string> <string name="gesture_error_title" msgid="469064941635578511">"Mēģiniet vēlreiz."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atpakaļ"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Lieliski!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Jūs sekmīgi veicāt nesen izmantoto lietotņu skatīšanas žestu."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Lai skatītu nesenās lietotnes, skārienpaliktnī ar trīs pirkstiem velciet augšup un turiet"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Pārslēgšanās starp lietotnēm"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Lieliski!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Jūs sekmīgi veicāt pārslēgšanās starp lietotnēm žestu."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Skatīt visas lietotnes"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tastatūrā nospiediet darbību taustiņu."</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Lieliski!"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index b478a5b38c4b..b53cec3636e3 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Се ажурира"</string> <string name="status_bar_work" msgid="5238641949837091056">"Работен профил"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Авионски режим"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Нема да го слушнете следниот аларм <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"во <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"во <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Добра сателитска врска"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Достапна е сателитска врска"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Сателитски SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Само итни повици или SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"нема сигнал"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"една цртичка"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Назад"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Известувања"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Кратенки на тастатурата"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Промени јазик на тастатура"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"или"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Бришење поим за пребарување"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Кратенки од тастатура"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системски апликации"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Мултитаскинг"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Поделен екран"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Внесување"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Кратенки за апликации"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Тековна апликација"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Приспособете ги кратенките"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Да се отстрани кратенката?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Да се ресетира на стандардните поставки?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Притиснете копче за да доделите кратенка"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"За да ја создадете кратенкава, притиснете го копчето за дејство и едно или повеќе други копчиња заедно"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Ова ќе ја избрише вашата приспособена кратенка трајно."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Ова ќе ги избрише трајно сите ваши приспособени кратенки."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пребарувајте кратенки"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Да, ресетирај"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Откажи"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Притиснете копче"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Комбинацијата на копчиња веќе се користи. Обидете се со друго копче."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Комбинацијата на копчиња веќе се користи. Обидете се со друга комбинација."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Кратенката не може да се постави."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Додај кратенка"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Врати се назад"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Оди на почетниот екран"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Прикажи ги неодамнешните апликации"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Сменете ги апликациите"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string> <string name="gesture_error_title" msgid="469064941635578511">"Обидете се повторно!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Одлично!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Го завршивте движењето за прегледување на неодамнешните апликации."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Повлечете нагоре со три прста на допирната подлога и задржете за да ги видите неодамнешните апликации"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Сменете ги апликациите"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Одлично!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Го завршивте движењето за менување апликации."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Прегледајте ги сите апликации"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Притиснете го копчето за дејство на тастатурата"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Браво!"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 4885595c860b..48ec2c05e95b 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"അപ്ഡേറ്റ് ചെയ്യുന്നു"</string> <string name="status_bar_work" msgid="5238641949837091056">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ഫ്ലൈറ്റ് മോഡ്"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-നുള്ള നിങ്ങളുടെ അടുത്ത അലാറം കേൾക്കില്ല"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>-ന്"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-ന്"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"സാറ്റലൈറ്റ്, മികച്ച കണക്ഷൻ"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"സാറ്റലൈറ്റ്, കണക്ഷൻ ലഭ്യമാണ്"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"സാറ്റലൈറ്റ് SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"എമർജൻസി കോളുകൾ അല്ലെങ്കിൽ SOS മാത്രം"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"സിഗ്നൽ ഇല്ല"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"ഒരു ബാർ"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"മടങ്ങുക"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"അറിയിപ്പുകൾ"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"കീബോർഡ് കുറുക്കുവഴികൾ"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"കീബോർഡ് ലേഔട്ട് മാറുക"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"അല്ലെങ്കിൽ"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"തിരയൽ ചോദ്യം മായ്ക്കുക"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"കീബോർഡ് കുറുക്കുവഴികൾ"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"സിസ്റ്റം ആപ്പുകൾ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"മൾട്ടിടാസ്കിംഗ്"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"സ്ക്രീൻ വിഭജന മോഡ്"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ഇൻപുട്ട്"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ആപ്പ് കുറുക്കുവഴികൾ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"നിലവിലെ ആപ്പ്"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"കുറുക്കുവഴികൾ ഇഷ്ടാനുസൃതമാക്കുക"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"കുറുക്കുവഴി നീക്കം ചെയ്യണോ?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ഡിഫോൾട്ടിലേക്ക് തിരികെ റീസെറ്റ് ചെയ്യണോ?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"കുറുക്കുവഴി അസൈൻ ചെയ്യാൻ കീ അമർത്തുക"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"ഈ കുറുക്കുവഴി സൃഷ്ടിക്കാൻ, ആക്ഷൻ കീയും ഒന്നോ അതിലധികമോ മറ്റ് കീകളും ഒരുമിച്ച് അമർത്തുക"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ഇത് നിങ്ങളുടെ ഇഷ്ടാനുസൃത കുറുക്കുവഴി ശാശ്വതമായി ഇല്ലാതാക്കും."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"നിങ്ങളുടെ എല്ലാ ഇഷ്ടാനുസൃത കുറുക്കുവഴികളും ശാശ്വതമായി ഇത് ഇല്ലാതാക്കും."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"തിരയൽ കുറുക്കുവഴികൾ"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ഉവ്വ്, റീസെറ്റ് ചെയ്യുക"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"റദ്ദാക്കുക"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"കീ അമർത്തുക"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"കീ കോമ്പിനേഷൻ ഇതിനകം ഉപയോഗത്തിലുണ്ട്. മറ്റൊരു കീ പരീക്ഷിക്കുക."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"കീ കോമ്പിനേഷൻ ഇതിനകം ഉപയോഗത്തിലുണ്ട്. മറ്റൊരു കോമ്പിനേഷൻ ശ്രമിക്കുക."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"കുറുക്കുവഴി സജ്ജീകരിക്കാനാകില്ല."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"കുറുക്കുവഴി ചേർക്കുക"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"മടങ്ങുക"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ഹോമിലേക്ക് പോകുക"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"ആപ്പുകൾ മാറുക"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"പൂർത്തിയായി"</string> <string name="gesture_error_title" msgid="469064941635578511">"വീണ്ടും ശ്രമിക്കുക!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"മടങ്ങുക"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"കൊള്ളാം!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക എന്ന ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"സമീപകാല ആപ്പുകൾ കാണുന്നതിന്, നിങ്ങളുടെ ടച്ച്പാഡിൽ മൂന്ന് വിരലുകൾ ഉപയോഗിച്ച് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്ത് പിടിക്കുക"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ആപ്പുകൾ മാറുക"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"കൊള്ളാം!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ആപ്പുകൾ മാറൽ ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"എല്ലാ ആപ്പുകളും കാണുക"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"നിങ്ങളുടെ കീബോർഡിലെ ആക്ഷൻ കീ അമർത്തുക"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"അഭിനന്ദനങ്ങൾ!"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 52dff9e8afdd..6effa0a5234b 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Шинэчилж байна"</string> <string name="status_bar_work" msgid="5238641949837091056">"Ажлын профайл"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Нислэгийн горим"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-т та дараагийн сэрүүлгээ сонсохгүй"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> цагт"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-т"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Хиймэл дагуул, холболт сайн байна"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Хиймэл дагуул, холболт боломжтой"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Хиймэл дагуул SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Зөвхөн яаралтай дуудлага эсвэл SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"дохио байхгүй"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"нэг шон"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Буцах"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Мэдэгдэл"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Гарын товчлол"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Гарын бүдүүвч рүү сэлгэх"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"эсвэл"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Хайлтын асуулгыг арилгах"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Товчлуурын шууд холбоос"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системийн аппууд"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Олон ажил зэрэг хийх"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Дэлгэцийг хуваах"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Оролт"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Аппын товчлол"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Одоогийн апп"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Товчлолыг өөрчлөх"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Товчлолыг хасах уу?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Өгөгдмөл рүү буцааж шинэчлэх үү?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Товчлол оноохын тулд товч дарна уу"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Энэ товчлолыг үүсгэхийн тулд Тусгай товч болон өөр нэг эсвэл түүнээс олон товчийг хамтад нь дарна уу"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Энэ нь таны захиалгат товчлолыг бүрмөсөн устгана."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Энэ нь таны бүх захиалгат товчлолыг бүрмөсөн устгана."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Товчлолууд хайх"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Тэгье, шинэчилье"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Цуцлах"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Товч дарна уу"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Товчийн хослолыг аль хэдийн ашиглаж байна. Өөр товч туршиж үзнэ үү."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Товчийн хослолыг аль хэдийн ашиглаж байна. Өөр хослол туршиж үзнэ үү."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Товчлол тохируулах боломжгүй."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Товчлол нэмэх"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Буцах"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Нүүр хуудас руу очих"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Саяхны аппуудыг харах"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Апп сэлгэх"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Болсон"</string> <string name="gesture_error_title" msgid="469064941635578511">"Дахин оролдоно уу!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Буцах"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Сайн байна!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Та саяхны аппуудыг харах зангааг гүйцэтгэсэн."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Саяхны аппуудыг харахын тулд мэдрэгч самбар дээрээ гурван хуруугаараа дээш шудраад, удаан дарна уу"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Апп сэлгэх"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Үнэхээр сайн ажиллалаа!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Та апп хооронд сэлгэх зангааг гүйцэтгэлээ."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Бүх аппыг харах"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Гар дээрх тусгай товчлуурыг дарна уу"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Сайн байна!"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 85ae835df9fe..77fd538ed398 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"अपडेट करत आहे"</string> <string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाईल"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"विमान मोड"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"तुम्ही तुमचा <xliff:g id="WHEN">%1$s</xliff:g> वाजता होणारा पुढील अलार्म ऐकणार नाही"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> वाजता"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> रोजी"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"सॅटेलाइट, चांगले कनेक्शन"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"सॅटेलाइट, कनेक्शन उपलब्ध"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"सॅटेलाइट SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"फक्त आणीबाणी कॉल किंवा SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"कोणताही सिग्नल नाही"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"एक बार"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"परत"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"सूचना"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"कीबोर्ड शॉर्टकट"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"कीबोर्ड लेआउट स्विच करा"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"किंवा"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"शोध क्वेरी साफ करा"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"कीबोर्ड शॉर्टकट"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"सिस्टीम अॅप्स"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"मल्टिटास्किंग"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"स्प्लिट स्क्रीन"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"इनपुट"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"अॅप शॉर्टकट"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"सध्याचे अॅप"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"शॉर्टकट कस्टमाइझ करा"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"शॉर्टकट काढून टाकायचा आहे का?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"डीफॉल्टवर पुन्हा रीसेट करायचे आहे का?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"शॉर्टकट असाइन करण्यासाठी की प्रेस करा"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"हा शॉर्टकट तयार करण्यासाठी, ॲक्शन की आणि एक किंवा त्याहून अधिक की एकत्र प्रेस करा"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"यामुळे तुमचा कस्टम शॉर्टकट कायमचा हटवला जाईल."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"हे तुमचे सर्व कस्टम शॉर्टकट कायमचे हटवेल."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"शोधण्यासाठी शॉर्टकट"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"होय, रीसेट करा"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"रद्द करा"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"की प्रेस करा"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"की कॉम्बिनेशन आधीपासून वापरले जात आहे. दुसरी की वापरून पहा."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"की कॉम्बिनेशन आधीपासून वापरले जात आहे. दुसरे कॉम्बिनेशन वापरून पहा."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"शॉर्टकट सेट करू शकत नाही."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"शॉर्टकट जोडा"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"मागे जा"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"होमवर जा"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"अलीकडील अॅप्स पहा"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"अॅप्स स्विच करा"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"पूर्ण झाले"</string> <string name="gesture_error_title" msgid="469064941635578511">"पुन्हा प्रयत्न करा!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"मागे जा"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"उत्तम कामगिरी!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"तुम्ही अलीकडील ॲप्स पाहण्याचे जेश्चर पूर्ण केले आहे."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"अलीकडील अॅप्स पाहण्यासाठी, तुमच्या टचपॅडवर तीन बोटांनी वर स्वाइप करून धरून ठेवा"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"अॅप्स स्विच करा"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"उत्तम कामगिरी!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"तुम्ही अॅप्स स्विच करणे जेश्चर पूर्ण केले आहे."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"सर्व अॅप्स पहा"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"तुमच्या कीबोर्डवर अॅक्शन की प्रेस करा"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"खूप छान!"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index b5f0d147f972..7aa95f09404d 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Mengemaskinikan"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mod pesawat"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar penggera yang seterusnya <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"pada <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"pada <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, sambungan yang baik"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, sambungan tersedia"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via Satelit"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Panggilan kecemasan atau SOS sahaja"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"tiada isyarat"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"satu bar"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Kembali"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Pemberitahuan"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Pintasan Papan Kekunci"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Tukar reka letak papan kekunci"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"atau"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Kosongkan pertanyaan carian"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Pintasan Papan Kekunci"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apl sistem"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Berbilang tugas"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Skrin pisah"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Pintasan apl"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Apl Semasa"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Sesuaikan pintasan"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Alih keluar pintasan?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Tetapkan kembali kepada lalai?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tekan kekunci untuk menetapkan pintasan"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Untuk membuat pintasan ini, tekan kekunci Tindakan dan sekurang-kurangnya satu kekunci lain bersama"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Tindakan ini akan memadamkan pintasan tersuai anda secara kekal."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Tindakan ini akan memadamkan semua pintasan tersuai anda secara kekal."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan carian"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ya, tetapkan semula"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Batal"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tekan kekunci"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Gabungan kekunci sudah digunakan. Cuba kekunci lain."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Gabungan kekunci sudah digunakan. Cuba kombinasi lain."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Pintasan tidak boleh ditetapkan."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Tambahkan pintasan"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Kembali"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Akses laman utama"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Lihat apl terbaharu"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Tukar apl"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Selesai"</string> <string name="gesture_error_title" msgid="469064941635578511">"Cuba lagi!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Syabas!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda telah melengkapkan gerak isyarat lihat apl terbaharu."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Untuk melihat apl terbaharu, leret ke atas dan tahan menggunakan tiga jari pada pad sentuh anda"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Tukar apl"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bagus!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Anda telah melengkapkan gerak isyarat menukar apl."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Lihat semua apl"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tekan kekunci tindakan pada papan kekunci anda"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Syabas!"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index d24c4a0b1631..d973d4066774 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"အပ်ဒိတ်လုပ်နေသည်"</string> <string name="status_bar_work" msgid="5238641949837091056">"အလုပ် ပရိုဖိုင်"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"လေယာဉ်ပျံမုဒ်"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> ၌သင့်နောက်ထပ် နှိုးစက်ကို ကြားမည်မဟုတ်ပါ"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ၌"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> တွင်"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ဂြိုဟ်တု၊ ချိတ်ဆက်မှု ကောင်းသည်"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ဂြိုဟ်တု၊ ချိတ်ဆက်မှု ရနိုင်သည်"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"အရေးပေါ်ဖုန်းခေါ်ခြင်း (သို့) SOS သီးသန့်"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>၊ <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>။"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"လိုင်းမရှိပါ"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"တစ်ဘား"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"နောက်သို့"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"အကြောင်းကြားချက်များ"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"ကီးဘုတ် ဖြတ်လမ်းများ"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"ကီးဘုတ်အပြင်အဆင် ပြောင်းခြင်း"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"သို့မဟုတ်"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ရှာဖွေစာလုံး ရှင်းထုတ်ရန်"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"လက်ကွက်ဖြတ်လမ်းများ"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"စနစ် အက်ပ်များ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"တစ်ပြိုင်နက် များစွာလုပ်ခြင်း"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ထည့်သွင်းမှု"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"အက်ပ်ဖြတ်လမ်းလင့်ခ်များ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"လက်ရှိအက်ပ်"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ဖြတ်လမ်းများ စိတ်ကြိုက်ပြင်ဆင်ခြင်း"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ဖြတ်လမ်းလင့်ခ် ဖယ်ရှားမလား။"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"မူရင်းသို့ ပြန်လည်ပြင်ဆင်သတ်မှတ်မလား။"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ဖြတ်လမ်းလင့်ခ်သတ်မှတ်ရန် ကီးကို နှိပ်ပါ"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"ဤဖြတ်လမ်းလင့်ခ် ပြုလုပ်ရန်အတွက် ‘လုပ်ဆောင်ချက်ကီး’ နှင့် တစ်ခု (သို့) တစ်ခုထက်ပိုသော အခြားကီးကို အတူနှိပ်ပါ"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"၎င်းသည် သင့်စိတ်ကြိုက် ဖြတ်လမ်းလင့်ခ်ကို အပြီးဖျက်ပါမည်။"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"၎င်းသည် သင့်စိတ်ကြိုက်ဖြတ်လမ်းလင့်ခ်အားလုံးကို အပြီးဖျက်မည်။"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ရှာဖွေစာလုံး ဖြတ်လမ်း"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ပြင်ဆင်ရန်"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"မလုပ်တော့"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ကီးကို နှိပ်ပါ"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"ကီးပေါင်းစပ်ခြင်းကို သုံးနေပြီးဖြစ်သည်။ အခြားကီးကို စမ်းကြည့်ပါ။"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"ကီးပေါင်းစပ်ခြင်းကို သုံးနေပြီးဖြစ်သည်။ အခြားပေါင်းစပ်မှုတစ်ခု စမ်းကြည့်ပါ။"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ဖြတ်လမ်းလင့်ခ် သတ်မှတ်၍မရပါ။"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ဖြတ်လမ်းလင့်ခ် ထည့်ရန်"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"နောက်သို့"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ပင်မစာမျက်နှာသို့ သွားရန်"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"မကြာသေးမီကအက်ပ်များကို ကြည့်ရန်"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"အက်ပ်များကူးပြောင်းခြင်း"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ပြီးပြီ"</string> <string name="gesture_error_title" msgid="469064941635578511">"ထပ်စမ်းကြည့်ပါ။"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ပြန်သွားရန်"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"တော်ပါပေသည်။"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"မကြာသေးမီကအက်ပ်များကို ကြည့်ခြင်းလက်ဟန် သင်ခန်းစာပြီးပါပြီ။"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"လတ်တလောအက်ပ်များကြည့်ရန် တာ့ချ်ပက်တွင် လက်သုံးချောင်းဖြင့် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"အက်ပ်များကူးပြောင်းခြင်း"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"တော်ပါပေသည်။"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"အက်ပ်ပြောင်းလက်ဟန် လုပ်ပြီးပါပြီ။"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"အက်ပ်အားလုံးကို ကြည့်ခြင်း"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ကီးဘုတ်တွင် လုပ်ဆောင်ချက်ကီး နှိပ်ပါ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"အလွန်ကောင်းပါသည်။"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 871ffe921f89..0d9e2760614c 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Oppdaterer"</string> <string name="status_bar_work" msgid="5238641949837091056">"Work-profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flymodus"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Du hører ikke neste innstilte alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellitt – god tilkobling"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellitt – tilkobling tilgjengelig"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-alarm via satellitt"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Bare nødanrop eller SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ikke noe signal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"én strek"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Tilbake"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Varsler"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Hurtigtaster"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Bytt tastaturoppsett"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"eller"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Fjern søket"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Hurtigtaster"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Systemapper"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Delt skjerm"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Inndata"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App-snarveier"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktiv app"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Tilpass snarveier"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Vil du fjerne hurtigtasten?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vil du tilbakestille til standard?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Trykk på en tast for å tilordne hurtigtasten"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"For å opprette denne snarveien, trykk på handlingstasten og én eller flere andre taster samtidig"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Dette fører til at den egendefinerte hurtigtasten slettes permanent."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Dette fører til at alle de egendefinerte snarveiene dine slettes permanent."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Søk etter snarveier"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Tilbakestill"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Avbryt"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Trykk på tasten"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tastekombinasjonen brukes allerede. Prøv en annen tast."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Tastekombinasjonen brukes allerede. Prøv en annen kombinasjon."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Kan ikke angi snarveien."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Legg til snarvei"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Gå tilbake"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Gå til startsiden"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se nylige apper"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Bytt app"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Ferdig"</string> <string name="gesture_error_title" msgid="469064941635578511">"Prøv på nytt."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbake"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bra jobbet!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du har fullført bevegelsen for å se nylige apper."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"For å se nylige apper, sveip opp og hold med tre fingre på styreflaten"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Bytt app"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bra jobbet!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Du har fullført bytt-app-bevegelsen."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Se alle apper"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Trykk på handlingstasten på tastaturet"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bra!"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 58307c49ada7..b1911596b2a1 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"अपडेट गरिँदै छ"</string> <string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाइल"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"हवाइजहाज मोड"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"तपाईँले आफ्नो अर्को अलार्म <xliff:g id="WHEN">%1$s</xliff:g> सुन्नुहुने छैन"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> मा"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> मा"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"स्याटलाइट, राम्रो कनेक्सन"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"स्याटलाइट, कनेक्सन उपलब्ध छ"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"स्याटलाइट SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"आपत्कालीन कल वा SOS मात्र"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>।"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"सिग्नल छैन"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"एउटा बार"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"पछाडि"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"सूचनाहरू"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"किबोर्ड सर्टकटहरू"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"किबोर्डको लेआउट बदल्नुहोस्"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"वा"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"किवर्ड हटाउनुहोस्"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"किबोर्डका सर्टकटहरू"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"सिस्टम एपहरू"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"मल्टिटास्किङ"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"स्प्लिट स्क्रिन"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"इनपुट"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"एपका सर्टकटहरू"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"हालको एप"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"सर्टकटहरू कस्टमाइज गर्नुहोस्"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"सर्टकट हटाउने हो?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"सर्टकट रिसेट गरी डिफल्ट बनाउने हो?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"सर्टकट असाइन गर्न की थिच्नुहोस्"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"यो सर्टकट बनाउन एक्सन की र एउटा वा सोभन्दा बढी की एकैचोटि थिच्नुहोस्"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"यसो गर्नुभयो भने तपाईंको कस्टम सर्टकट सदाका लागि मेटिने छ।"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"तपाईंले यसो गर्नुभयो भने तपाईंका सबै कस्टम सर्टकटहरू सदाका लागि मेटाइने छन्।"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"सर्टकटहरू खोज्नुहोस्"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"अँ, रिसेट गर्नुहोस्"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"रद्द गर्नुहोस्"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"की थिच्नुहोस्"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"यो की कम्बिनेसन प्रयोग गरिसकिएको छ। अर्कै की प्रयोग गरी हेर्नुहोस्।"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"यो की कम्बिनेसन प्रयोग गरिसकिएको छ। अर्कै कम्बिनेसन असाइन गरी हेर्नुहोस्।"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"सर्टकट सेट गर्न सकिएन।"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"सर्टकट हाल्नुहोस्"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"पछाडि जानुहोस्"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"होम स्क्रिनमा जानुहोस्"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"हालसालै चलाइएका एपहरू हेर्नुहोस्"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"एपहरू बदल्नुहोस्"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"सम्पन्न भयो"</string> <string name="gesture_error_title" msgid="469064941635578511">"फेरि प्रयास गर्नुहोस्!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"पछाडि जानुहोस्"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"अद्भुत!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"तपाईंले जेस्चर प्रयोग गरी हालसालै चलाइएका एपहरू हेर्ने तरिका सिक्नुभएको छ।"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"हालसालैका एपहरू हेर्न तीन औँला प्रयोग गरी टचप्याडमा माथितिर स्वाइप गर्नुहोस् र होल्ड गर्नुहोस्"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"एपहरू बदल्नुहोस्"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"अद्भुत!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"तपाईंले एपहरू बदल्ने जेस्चर प्रयोग गर्ने तरिका सिक्नुभयो।"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"सबै एपहरू हेर्नुहोस्"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"आफ्नो किबोर्डमा भएको एक्सन की थिच्नुहोस्"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"स्याबास!"</string> diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index a77f5e4629c1..326be99b8a65 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -108,8 +108,14 @@ <color name="people_tile_background">@color/material_dynamic_secondary20</color> - <!-- Dark Theme colors for notification shade/scrim --> - <color name="shade_panel">@android:color/system_accent1_900</color> + <!-- Dark theme base colors for notification shade/scrim, the alpha component is adjusted + programmatically to match the spec --> + <color name="shade_panel">@android:color/system_accent1_800</color> + <color name="surface_effect_0">@android:color/system_accent1_800</color> + + <!-- todo(b/388891904) Remove updated color references once they are available. --> + <color name="shade_panel_base">@color/shade_panel</color> + <color name="notification_scrim_base">@color/surface_effect_0</color> <!-- Keyboard shortcut helper dialog --> <color name="ksh_key_item_color">@*android:color/system_on_surface_variant_dark</color> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 6e8d328c1896..a3d8856625f4 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Updaten"</string> <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Je hoort je volgende wekker niet <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"om <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"op <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelliet, goede verbinding"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelliet, verbinding beschikbaar"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satelliet"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Alleen noodoproepen of SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"geen signaal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"1 streepje"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Terug"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Meldingen"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Sneltoetsen"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Toetsenbordindeling wisselen"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"of"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Zoekopdracht wissen"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Sneltoetsen"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Systeem-apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Gesplitst scherm"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Invoer"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App-sneltoetsen"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Huidige app"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Snelkoppelingen aanpassen"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Sneltoets verwijderen?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Resetten naar standaard?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Druk op de toets om de sneltoets toe te wijzen"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Als je deze sneltoets wilt maken, druk je tegelijkertijd op de actietoets en een of meer andere toetsen"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Hiermee wordt je aangepaste sneltoets definitief verwijderd."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Hiermee worden al je aangepaste snelkoppelingen definitief verwijderd."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sneltoetsen zoeken"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ja, resetten"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuleren"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Druk op een toets"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Toetsencombinatie is al in gebruik. Probeer een andere toets."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Toetsencombinatie is al in gebruik. Probeer een andere combinatie."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Sneltoets kan niet worden ingesteld."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Snelkoppeling toevoegen"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Terug"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Naar startscherm"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Recente apps bekijken"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Wisselen tussen apps"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klaar"</string> <string name="gesture_error_title" msgid="469064941635578511">"Probeer het nog eens."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Terug"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Goed gedaan!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Je weet nu hoe je het gebaar Recente apps bekijken maakt."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Als je recente apps wilt bekijken, swipe je met 3 vingers omhoog op de touchpad en houd je vast"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Wisselen tussen apps"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Goed werk!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Je weet nu hoe je het gebaar om van app te wisselen maakt."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Alle apps bekijken"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Druk op de actietoets op het toetsenbord"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Goed gedaan!"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 9986c11b49fd..fa89a4858cdc 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"ଅପଡେଟ ହେଉଛି"</string> <string name="status_bar_work" msgid="5238641949837091056">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ଏୟାରପ୍ଲେନ ମୋଡ"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>ବେଳେ ଆପଣ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ହେଲେ"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ବେଳେ"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ସାଟେଲାଇଟ, ଭଲ କନେକ୍ସନ"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ସାଟେଲାଇଟ, କନେକ୍ସନ ଉପଲବ୍ଧ"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ସେଟେଲାଇଟ SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"କେବଳ ଜରୁରୀକାଳୀନ କଲ କିମ୍ବା SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>।"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"କୌଣସି ସିଗନାଲ ନାହିଁ"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"ଗୋଟିଏ ବାର"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"ଫେରନ୍ତୁ"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"ବିଜ୍ଞପ୍ତି"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"କୀବୋର୍ଡ ସର୍ଟକଟ"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"କୀ\'ବୋର୍ଡ୍ର ଲେଆଉଟ୍କୁ ବଦଳାନ୍ତୁ"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"କିମ୍ବା"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ସର୍ଚ୍ଚ କ୍ୱେରୀକୁ ଖାଲି କରନ୍ତୁ"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"କୀବୋର୍ଡ ସର୍ଟକଟ"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"ସିଷ୍ଟମ ଆପ୍ସ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ମଲ୍ଟିଟାସ୍କିଂ"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ଇନପୁଟ"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ଆପ ସର୍ଟକଟ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ବର୍ତ୍ତମାନର ଆପ"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ସର୍ଟକଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ସର୍ଟକଟକୁ କାଢ଼ି ଦେବେ?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ଡିଫଲ୍ଟରେ ପୁଣି ରିସେଟ କରିବେ?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ସର୍ଟକଟ ଆସାଇନ କରିବା ପାଇଁ କୀ\'କୁ ଦବାନ୍ତୁ"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"ଏହି ସର୍ଟକଟ ତିଆରି କରିବାକୁ ଏକାଠି ଆକ୍ସନ କୀ କିମ୍ବା ଗୋଟିଏ ବା ଅଧିକ ଅନ୍ୟ କୀ ଦବାନ୍ତୁ"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ଏହା ଆପଣଙ୍କ କଷ୍ଟମ ସର୍ଟକଟକୁ ସ୍ଥାୟୀ ଭାବେ ଡିଲିଟ କରିଦେବ।"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ଏହା ଆପଣଙ୍କର ସମସ୍ତ କଷ୍ଟମ ସର୍ଟକଟକୁ ସ୍ଥାୟୀ ଭାବେ ଡିଲିଟ କରିଦେବ।"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ସର୍ଚ୍ଚ ସର୍ଟକଟ"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ହଁ, ରିସେଟ କରନ୍ତୁ"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ବାତିଲ କରନ୍ତୁ"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"କୀ ଦବାନ୍ତୁ"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"କୀ କମ୍ବିନେସନ ପୂର୍ବରୁ ବ୍ୟବହାର କରାଯାଉଛି। ଅନ୍ୟ ଏକ କୀ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ।"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"କୀ କମ୍ବିନେସନ ପୂର୍ବରୁ ବ୍ୟବହାର କରାଯାଉଛି। ଅନ୍ୟ ଏକ କମ୍ବିନେସନ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ।"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ସର୍ଟକଟ ସେଟ କରାଯାଇପାରିବ ନାହିଁ।"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ସର୍ଟକଟ ଯୋଗ କରନ୍ତୁ"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ପଛକୁ ଫେରନ୍ତୁ"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ହୋମକୁ ଯାଆନ୍ତୁ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ବର୍ତ୍ତମାନର ଆପ୍ସ ଭ୍ୟୁ କରନ୍ତୁ"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"ଆପ୍ସକୁ ସୁଇଚ କରନ୍ତୁ"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ହୋଇଗଲା"</string> <string name="gesture_error_title" msgid="469064941635578511">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ପଛକୁ ଫେରନ୍ତୁ"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ବଢ଼ିଆ କାମ!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ଆପଣ ବର୍ତ୍ତମାନର ଆପ୍ସ ଜେଶ୍ଚରକୁ ଭ୍ୟୁ କରିବା ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ବର୍ତ୍ତମାନର ଆପ୍ସ ଭ୍ୟୁ କରିବାକୁ, ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠି ବ୍ୟବହାର କରି ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ଆପ୍ସକୁ ସୁଇଚ କରନ୍ତୁ"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ବଢ଼ିଆ କାମ!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ଆପଣ ସୁଇଚ ଆପ୍ସ ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ସବୁ ଆପ ଭ୍ୟୁ କରନ୍ତୁ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ଆପଣଙ୍କର କୀବୋର୍ଡରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ବହୁତ ବଢ଼ିଆ!"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 45888847bc2e..a0c06122b7a4 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"ਅੱਪਡੇਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string> <string name="status_bar_work" msgid="5238641949837091056">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"ਤੁਸੀਂ <xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ ਆਪਣਾ ਅਗਲਾ ਅਲਾਰਮ ਨਹੀਂ ਸੁਣੋਗੇ"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ਸੈਟੇਲਾਈਟ, ਕਨੈਕਸ਼ਨ ਵਧੀਆ ਹੈ"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ਸੈਟੇਲਾਈਟ, ਕਨੈਕਸ਼ਨ ਉਪਲਬਧ ਹੈ"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ਸੈਟੇਲਾਈਟ SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"ਸਿਰਫ਼ ਐਮਰਜੈਂਸੀ ਕਾਲਾਂ ਜਾਂ ਸਹਾਇਤਾ"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ਕੋਈ ਸਿਗਨਲ ਨਹੀਂ"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"ਇੱਕ ਸਿਗਨਲ ਪੱਟੀ"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"ਪਿੱਛੇ"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"ਸੂਚਨਾਵਾਂ"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"ਕੀ-ਬੋਰਡ ਖਾਕਾ ਬਦਲੋ"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ਜਾਂ"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ਖੋਜ ਪੁੱਛਗਿੱਛ ਕਲੀਅਰ ਕਰੋ"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"ਸਿਸਟਮ ਐਪਾਂ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ਮਲਟੀਟਾਸਕਿੰਗ"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ਇਨਪੁੱਟ"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ਐਪ ਸ਼ਾਰਟਕੱਟ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ਮੌਜੂਦਾ ਐਪ"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ਸ਼ਾਰਟਕੱਟਾਂ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ਕੀ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਹਟਾਉਣਾ ਹੈ?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ਕੀ ਵਾਪਸ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ \'ਤੇ ਰੀਸੈੱਟ ਕਰਨਾ ਹੈ?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ਸ਼ਾਰਟਕੱਟ ਨਿਰਧਾਰਿਤ ਕਰਨ ਲਈ ਕੁੰਜੀ ਦਬਾਓ"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"ਇਸ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਬਣਾਉਣ ਲਈ, ਕਾਰਵਾਈ ਕੁੰਜੀ ਅਤੇ ਇੱਕ ਜਾਂ ਇੱਕ ਤੋਂ ਵੱਧ ਕੁੰਜੀਆਂ ਨੂੰ ਇਕੱਠੇ ਦਬਾਓ"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ਇਸ ਨਾਲ ਤੁਹਾਡੇ ਵਿਉਂਤੇ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਪੱਕੇ ਤੌਰ \'ਤੇ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ਇਸ ਨਾਲ ਤੁਹਾਡੇ ਸਾਰੇ ਵਿਉਂਤਬੱਧ ਸ਼ਾਰਟਕੱਟ ਪੱਕੇ ਤੌਰ \'ਤੇ ਮਿਟ ਜਾਣਗੇ।"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ਸ਼ਾਰਟਕੱਟ ਖੋਜੋ"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ਹਾਂ, ਰੀਸੈੱਟ ਕਰੋ"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ਰੱਦ ਕਰੋ"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ਕੁੰਜੀ ਦਬਾਓ"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"ਕੁੰਜੀ ਸੁਮੇਲ ਪਹਿਲਾਂ ਹੀ ਵਰਤੋਂ ਵਿੱਚ ਹੈ। ਕੋਈ ਹੋਰ ਕੁੰਜੀ ਵਰਤ ਕੇ ਦੇਖੋ।"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"ਕੁੰਜੀ ਸੁਮੇਲ ਪਹਿਲਾਂ ਹੀ ਵਰਤੋਂ ਵਿੱਚ ਹੈ। ਕੋਈ ਹੋਰ ਸੁਮੇਲ ਵਰਤ ਕੇ ਦੇਖੋ।"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਸੈੱਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ਸ਼ਾਰਟਕੱਟ ਸ਼ਾਮਲ ਕਰੋ"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ਵਾਪਸ ਜਾਓ"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ਹੋਮ \'ਤੇ ਜਾਓ"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"ਐਪਾਂ ਵਿਚਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ਹੋ ਗਿਆ"</string> <string name="gesture_error_title" msgid="469064941635578511">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ਵਾਪਸ ਜਾਓ"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"ਬਹੁਤ ਵਧੀਆ!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ਤੁਸੀਂ \'ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ ਹੈ।"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ਹਾਲੀਆ ਐਪਾਂ ਦੇਖਣ ਲਈ, ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਤਿੰਨ ਉਂਗਲਾਂ ਵਰਤ ਕੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਕੇ ਰੋਕ ਕੇ ਰੱਖੋ"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ਐਪਾਂ ਵਿਚਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ਬਹੁਤ ਵਧੀਆ!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ਤੁਸੀਂ ਐਪ ਸਵਿੱਚ ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ਸਾਰੀਆਂ ਐਪਾਂ ਦੇਖੋ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ਆਪਣੇ ਕੀ-ਬੋਰਡ \'ਤੇ ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਦਬਾਓ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ਬਹੁਤ ਵਧੀਆ!"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 67ca4393ee64..031311741a55 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Aktualizuję"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil służbowy"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Tryb samolotowy"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nie usłyszysz swojego następnego alarmu <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"o <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"w: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelita – połączenie dobre"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelita – połączenie dostępne"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satelitarne połączenie alarmowe"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Tylko połączenia alarmowe lub SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"brak sygnału"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"1 pasek"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Wstecz"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Powiadomienia"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Skróty klawiszowe"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Przełącz układ klawiatury"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"lub"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Wyczyść wyszukiwanie hasło"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Skróty klawiszowe"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplikacje systemowe"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Wielozadaniowość"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Podzielony ekran"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Wprowadzanie"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Skróty do aplikacji"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Bieżąca aplikacja"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Dostosuj skróty"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Usunąć skrót?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Zresetować do ustawień domyślnych?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Naciśnij klawisz, aby przypisać skrót"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Aby utworzyć ten skrót, naciśnij jednocześnie klawisz działania i co najmniej 1 inny klawisz"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Spowoduje to trwałe usunięcie skrótu niestandardowego."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Spowoduje to trwałe usunięcie wszystkich skrótów niestandardowych."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Szukaj skrótów"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Tak, zresetuj"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Anuluj"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Naciśnij klawisz"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ta kombinacja klawiszy jest już używana. Użyj innego klawisza."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Ta kombinacja klawiszy jest już używana. Użyj innej."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Nie można ustawić skrótu."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Dodaj skrót"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Wróć"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Otwórz stronę główną"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Wyświetlanie ostatnich aplikacji"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Przełączanie aplikacji"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotowe"</string> <string name="gesture_error_title" msgid="469064941635578511">"Spróbuj jeszcze raz"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Wróć"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Brawo!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Znasz już gest wyświetlania ostatnio używanych aplikacji."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Aby wyświetlić ostatnie aplikacje, przesuń 3 palcami w górę na touchpadzie i przytrzymaj"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Przełączanie aplikacji"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Brawo!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Gest do przełączania aplikacji został opanowany."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Wyświetl wszystkie aplikacje"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Naciśnij klawisz działania na klawiaturze"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Brawo!"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index ead72a21e432..e21554cb9e6f 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Atualizando"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, conexão boa"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexão disponível"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satélite"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Apenas chamadas de emergência ou SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"sem sinal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"uma barra"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Voltar"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notificações"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Atalhos do teclado"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Alterar layout do teclado"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Limpar a consulta de pesquisa"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Atalhos do teclado"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apps do sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarefas"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Tela dividida"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atalhos de apps"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App atual"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar atalhos"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remover atalho?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Redefinir para o padrão?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pressione a tecla para atribuir o atalho"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Para criar esse atalho, pressione a tecla de ação e uma ou mais outras teclas"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Essa ação vai excluir permanentemente seu atalho personalizado."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Essa ação vai excluir permanentemente todos os seus atalhos personalizados."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pesquisar atalhos"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sim, redefinir"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pressione a tecla"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Essa combinação de teclas já está em uso. Tente outra tecla."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Essa combinação de teclas já está em uso. Tente outra."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Não é possível definir o atalho."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Adicionar atalho"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Voltar"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir para a página inicial"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver os apps recentes"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Mudar de app"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluído"</string> <string name="gesture_error_title" msgid="469064941635578511">"Tente de novo"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Se quiser ver os apps recentes, deslize para cima e pressione o touchpad com três dedos"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Mudar de app"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Muito bem!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Você concluiu o gesto para mudar de app."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todos os apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pressione a tecla de ação no teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 303a2808d552..f5c29d485130 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"A atualizar"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avião"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Não vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"em <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, boa ligação"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, ligação disponível"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satélite SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Apenas chamadas de emergência ou SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"sem sinal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"1 barra"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Anterior"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notificações"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Atalhos de teclado"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Alterar esquema de teclado"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Limpar consulta de pesquisa"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Atalhos de teclado"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apps do sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ecrã dividido"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atalhos de apps"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App atual"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalize os atalhos"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remover atalho?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Repor para a predefinição?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Prima a tecla para atribuir o atalho"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Para criar este atalho, prima a tecla de ação e uma ou mais teclas adicionais em simultâneo"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Esta ação elimina o atalho personalizado permanentemente."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Esta ação elimina todos os seus atalhos personalizados permanentemente."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pesquisar atalhos"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sim, repor"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Prima a tecla"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"A combinação de teclas já está a ser usada. Experimente outra tecla."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"A combinação de teclas já está a ser usada. Experimente outra combinação."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Não é possível definir o atalho."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Adicionar atalho"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Voltar"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Aceder ao ecrã principal"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver apps recentes"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Mudar de app"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluir"</string> <string name="gesture_error_title" msgid="469064941635578511">"Tente novamente!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Concluiu o gesto para ver as apps recentes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Para ver as apps recentes, deslize rapidamente para cima sem soltar com 3 dedos no touchpad"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Mudar de app"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Muito bem!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Concluiu o gesto para alternar entre apps."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todas as apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Prima a tecla de ação no teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index ead72a21e432..e21554cb9e6f 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Atualizando"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satélite, conexão boa"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satélite, conexão disponível"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS via satélite"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Apenas chamadas de emergência ou SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"sem sinal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"uma barra"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Voltar"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notificações"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Atalhos do teclado"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Alterar layout do teclado"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Limpar a consulta de pesquisa"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Atalhos do teclado"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apps do sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarefas"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Tela dividida"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atalhos de apps"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App atual"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar atalhos"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remover atalho?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Redefinir para o padrão?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pressione a tecla para atribuir o atalho"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Para criar esse atalho, pressione a tecla de ação e uma ou mais outras teclas"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Essa ação vai excluir permanentemente seu atalho personalizado."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Essa ação vai excluir permanentemente todos os seus atalhos personalizados."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pesquisar atalhos"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sim, redefinir"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pressione a tecla"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Essa combinação de teclas já está em uso. Tente outra tecla."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Essa combinação de teclas já está em uso. Tente outra."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Não é possível definir o atalho."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Adicionar atalho"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Voltar"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ir para a página inicial"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ver os apps recentes"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Mudar de app"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluído"</string> <string name="gesture_error_title" msgid="469064941635578511">"Tente de novo"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Muito bem!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Se quiser ver os apps recentes, deslize para cima e pressione o touchpad com três dedos"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Mudar de app"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Muito bem!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Você concluiu o gesto para mudar de app."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todos os apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pressione a tecla de ação no teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index afd18f12cbf5..7a9ea1fa10fd 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Se actualizează"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil de serviciu"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mod Avion"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nu vei auzi următoarea alarmă <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"la <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, conexiune bună"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, conexiune disponibilă"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS prin satelit"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Numai apeluri de urgență sau SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"fără semnal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"o bară"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Înapoi"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notificări"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Comenzi rapide de la tastatură"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Schimbă aspectul tastaturii"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"sau"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Șterge termenul de căutare"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Comenzi rapide de la tastatură"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplicații de sistem"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ecran împărțit"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Intrare"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Comenzi rapide pentru aplicații"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicația actuală"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizează comenzile rapide"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Elimini comanda rapidă?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Resetezi la valorile prestabilite?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Apasă tasta pentru a atribui comanda rapidă"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Pentru a crea această comandă rapidă, apasă tasta de acțiuni și una sau mai multe taste simultan"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Astfel, se va șterge definitiv comanda rapidă personalizată."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Astfel, se vor șterge definitiv toate comenzile rapide personalizate."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Comenzi directe de căutare"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Resetează"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Anulează"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Apasă tasta"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Combinația de taste este deja folosită. Încearcă altă tastă."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Combinația de taste este deja folosită. Încearcă altă combinație."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Comanda rapidă nu poate fi setată."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Adaugă o comandă rapidă"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Înapoi"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Înapoi la pagina de pornire"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Vezi aplicațiile recente"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Comută între aplicații"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gata"</string> <string name="gesture_error_title" msgid="469064941635578511">"Încearcă din nou!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Înapoi"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Excelent!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ai finalizat gestul pentru afișarea aplicațiilor recente."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Ca să vezi aplicațiile recente, glisează în sus și ține apăsat cu trei degete pe touchpad"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Comută între aplicații"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Excelent!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ai finalizat gestul de trecere la altă aplicație."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Vezi toate aplicațiile"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Apasă tasta de acțiuni de pe tastatură"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Felicitări!"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 10dc51d71683..f5b33742c8cb 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Обновление"</string> <string name="status_bar_work" msgid="5238641949837091056">"Рабочий профиль"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Режим полета"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Следующий будильник: <xliff:g id="WHEN">%1$s</xliff:g>. Звук отключен."</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Спутниковая связь, хорошее качество соединения"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Доступно соединение по спутниковой связи"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Спутниковый SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Только экстренные вызовы или спутниковый SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"нет сигнала"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"одно деление"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Назад"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Уведомления"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Сочетания клавиш"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Переключение раскладки"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"или"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Удалить поисковый запрос"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Сочетания клавиш"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системные приложения"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Многозадачность"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Разделение экрана"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Ввод"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Приложения"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Это приложение"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Настройки сочетаний клавиш"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Удалить сочетание клавиш?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Сбросить настройки?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Нажмите клавишу, чтобы назначить сочетание клавиш."</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Чтобы сохранить сочетание клавиш, нажмите одновременно клавишу действия и одну или несколько дополнительных клавиш"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Настроенное сочетание будет безвозвратно удалено."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Все настроенные сочетания клавиш будут безвозвратно удалены."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Найти"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Сбросить"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Отмена"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Нажмите клавишу"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Это сочетание клавиш уже используется. Попробуйте другое."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Это сочетание клавиш уже используется. Попробуйте другое."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Это сочетание клавиш выбрать нельзя."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Добавить сочетание клавиш"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Назад"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"На главный экран"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Просмотр недавних приложений"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Переход в другое приложение"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string> <string name="gesture_error_title" msgid="469064941635578511">"Попробуйте ещё раз"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Отлично!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Вы выполнили жест для просмотра недавних приложений."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Чтобы увидеть недавние приложения, проведите по сенсорной панели тремя пальцами вверх и удерживайте."</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Переход в другое приложение"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Отлично!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Вы выполнили жест перехода в другое приложение."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Все приложения"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Нажмите клавишу действия на клавиатуре."</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Блестяще!"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 5a7a6a377527..a9ea2ae68a89 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"යාවත්කාලීන කිරීම"</string> <string name="status_bar_work" msgid="5238641949837091056">"කාර්යාල පැතිකඩ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ගුවන්යානා ප්රකාරය"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"ඔබට ඔබේ ඊළඟ එලාමය <xliff:g id="WHEN">%1$s</xliff:g> නොඇසෙනු ඇත"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ට"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> දී"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"චන්ද්රිකාව, හොඳ සම්බන්ධතාවයක්"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"චන්ද්රිකාව, සම්බන්ධතාවය තිබේ"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"චන්ද්රිකා SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"හදිසි ඇමතුම් හෝ SOS පමණි"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"සංඥාව නැත"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"තීරු එකක්"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"ආපසු"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"දැනුම්දීම්"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"යතුරු පුවරු කෙටිමං"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"යතුරුපුවරු පිරිසැලසුම මාරු කරන්න"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"හෝ"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"සෙවීම් විමසුම හිස් කරන්න"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"යතුරු පුවරු කෙටිමං"</string> @@ -1432,16 +1432,17 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"පද්ධති යෙදුම්"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"බහුකාර්ය"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"බෙදුම් තිරය"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ආදානය"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"යෙදුම් කෙටිමං"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"වත්මන් යෙදුම"</string> <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"ප්රවේශ්යතාව"</string> <string name="shortcut_helper_title" msgid="8567500639300970049">"යතුරු පුවරු කෙටි මං"</string> - <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) --> - <skip /> + <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"කෙටිමං අභිරුචිකරණය කරන්න"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"කෙටිමඟ ඉවත් කරන්න ද?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"පෙරනිමියට යළි සකසන්න ද?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"කෙටිමඟ පැවරීමට යතුර ඔබන්න"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"මෙම කෙටිමඟ නිර්මාණය කිරීමට, ක්රියාකාරී යතුර සහ තවත් යතුරු එකක් හෝ කිහිපයක් එකවර ඔබන්න"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"මෙය ඔබේ අභිරුචි කෙටිමඟ ස්ථිරවම මකනු ඇත."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"මෙය ඔබේ සියලු අභිරුචි කෙටිමං ස්ථිරවම මකනු ඇත."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"කෙටි මං සොයන්න"</string> @@ -1463,13 +1464,11 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ඔව්, යළි සකසන්න"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"අවලංගු කරන්න"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"යතුර ඔබන්න"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"යතුරු සංයෝජනය දැනටමත් භාවිත වේ. වෙනත් යතුරක් උත්සාහ කරන්න."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"යතුරු සංයෝජනය දැනටමත් භාවිත වේ. තවත් සංයෝජනයක් උත්සාහ කරන්න."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"කෙටිමඟ සැකසිය නොහැක."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> - <!-- no translation found for shortcut_helper_add_shortcut_button_label (7655779534665954910) --> - <skip /> - <!-- no translation found for shortcut_helper_delete_shortcut_button_label (3148773472696137052) --> - <skip /> + <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"කෙටිමඟ එක් කරන්න"</string> + <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"කෙටිමඟ මකන්න"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"ඔබේ යතුරු පුවරුව භාවිතයෙන් සංචාලනය කරන්න"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"යතුරුපුවරු කෙටිමං ඉගෙන ගන්න"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"ඔබේ ස්පර්ශ පෑඩ් භාවිතයෙන් සංචාලනය කරන්න"</string> @@ -1479,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ආපසු යන්න"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"මුල් පිටුවට යන්න"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"මෑත යෙදුම් බලන්න"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"යෙදුම් මාරු කරන්න"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"නිමයි"</string> <string name="gesture_error_title" msgid="469064941635578511">"නැවත උත්සාහ කරන්න!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ආපස්සට යන්න"</string> @@ -1496,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"අනර්ඝ වැඩක්!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ඔබ මෑත යෙදුම් ඉංගිත බැලීම සම්පූර්ණ කර ඇත."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"මෑත කාලීන යෙදුම් බැලීමට, ඔබේ ස්පර්ශක පෑඩයේ ඇඟිලි තුනක් භාවිතයෙන් ඉහළට ස්වයිප් කරගෙන සිටින්න"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"යෙදුම් මාරු කරන්න"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"අනර්ඝ වැඩක්!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ඔබ යෙදුම් මාරු කිරීමේ ඉංගිතය සම්පූර්ණ කර ඇත."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"සියලු යෙදුම් බලන්න"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ඔබේ යතුරු පුවරුවේ ක්රියාකාරී යතුර ඔබන්න"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"හොඳින් කළා!"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index d2d9cdeed413..406f423a18d0 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Aktualizuje sa"</string> <string name="status_bar_work" msgid="5238641949837091056">"Pracovný profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Režim v lietadle"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Váš budík o <xliff:g id="WHEN">%1$s</xliff:g> sa nespustí"</string> <string name="alarm_template" msgid="2234991538018805736">"o <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobrá kvalita pripojenia"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, pripojenie je k dispozícii"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Pomoc cez satelit"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Len tiesňové volania alebo pomoc v tiesni"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"žiadny signál"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"jedna čiarka"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Späť"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Upozornenia"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Klávesové skratky"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Prepnúť rozloženie klávesnice"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"alebo"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Vymazať vyhľadávací dopyt"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Klávesové skratky"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Systémové aplikácie"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Rozdelená obrazovka"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Vstup"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Skratky aplikácií"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuálna aplikácia"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Prispôsobenie skratiek"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Chcete skratku odstrániť?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Chcete resetovať na predvolené nastavenie?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Stlačením klávesa priraďte skratku"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Ak chcete vytvoriť túto skratku, stlačte súčasne akčný kláves a minimálne jeden ďalší kláves"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Týmto natrvalo odstránite vlastnú skratku."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Týmto natrvalo odstránite všetky vlastné odkazy."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prehľadávať skratky"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Áno, resetovať"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Zrušiť"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Stlačte kláves"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinácia klávesov sa už používa. Skúste iný kláves."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Kombinácia klávesov sa už používa. Skúste inú kombináciu."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Skratku nie je možné nastaviť."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Pridať skratku"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Prechod späť"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Prejsť na plochu"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Zobrazenie nedávnych aplikácií"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Prepínanie aplikácií"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hotovo"</string> <string name="gesture_error_title" msgid="469064941635578511">"Skúste to znova."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Prejdenie späť"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Skvelé!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Použili ste gesto na zobrazenie nedávnych aplikácií."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Ak si chcete zobraziť nedávne aplikácie, potiahnite troma prstami na touchpade nahor a pridržte ich"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Prepínanie aplikácií"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Skvelé!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Dokončili ste gesto na prepnutie aplikácií."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Zobrazenie všetkých aplikácií"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Stlačte na klávesnici akčný kláves"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Dobre!"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index c473962ca1ba..7127bed39f6b 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Posodabljanje"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil za Android Work"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Način za letalo"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Naslednjega alarma ob <xliff:g id="WHEN">%1$s</xliff:g> ne boste slišali"</string> <string name="alarm_template" msgid="2234991538018805736">"ob <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ob tem času: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satelit, dobra povezava"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satelit, povezava je na voljo"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS prek satelita"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Samo klici v sili ali SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ni signala"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"ena črtica"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Nazaj"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Obvestila"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Bližnjične tipke"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Preklop postavitve tipkovnice"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ali"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Čiščenje iskalne poizvedbe"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Bližnjične tipke"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistemske aplikacije"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Večopravilnost"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Razdeljen zaslon"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Vnos"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Bližnjice do aplikacij"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Trenutna aplikacija"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Prilagajanje bližnjic"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Želite odstraniti bližnjico?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Želite ponastaviti na privzete bližnjice?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite tipko za dodelitev bližnjice"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Če želite ustvariti to bližnjico, hkrati pritisnite tipko za dejanja in eno ali več drugih tipk"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"S tem boste trajno izbrisali bližnjico po meri."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"S tem boste trajno izbrisali vse bližnjice po meri."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Iskanje po bližnjicah"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Da"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Prekliči"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipko"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinacija tipk je že v uporabi. Poskusite z drugo tipko."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Kombinacija tipk je že v uporabi. Poskusite drugo kombinacijo."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Bližnjice ni mogoče nastaviti."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Dodajanje bližnjice"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Pomik nazaj"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Pomik na začetni zaslon"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Ogled nedavnih aplikacij"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Preklop aplikacij"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Končano"</string> <string name="gesture_error_title" msgid="469064941635578511">"Poskusite znova"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazaj"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Odlično!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvedli ste potezo za ogled nedavnih aplikacij."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Za ogled nedavnih aplikacij povlecite s tremi prsti navzgor po sledilni ploščici in pridržite"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Preklop aplikacij"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Odlično!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Izvedli ste potezo za preklop med aplikacijami."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ogled vseh aplikacij"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipko za dejanja na tipkovnici"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 3c7d05b2e318..b02434a810a9 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Po përditësohet"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profili i punës"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modaliteti i aeroplanit"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nuk do ta dëgjosh alarmin e radhës në <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"në <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"në <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Sateliti. Lidhje e mirë"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Sateliti. Ofrohet lidhje"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS satelitor"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Vetëm telefonata urgjence ose SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"nuk ka sinjal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"një vijë"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Prapa"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Njoftimet"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Shkurtoret e tastierës"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Ndërro strukturën e tastierës"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ose"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Pastro pyetjen e kërkimit"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Shkurtoret e tastierës"</string> @@ -1432,16 +1432,17 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplikacionet e sistemit"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Kryerja e shumë detyrave"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ekrani i ndarë"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Hyrja"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Shkurtoret e aplikacionit"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplikacioni aktual"</string> <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Qasshmëria"</string> <string name="shortcut_helper_title" msgid="8567500639300970049">"Shkurtoret e tastierës"</string> - <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) --> - <skip /> + <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizo shkurtoret"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Të hiqet shkurtorja?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Të rivendosen përsëri te parazgjedhjet?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Shtyp tastin për të caktuar shkurtoren"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Për të krijuar këtë shkurtore, shtyp tastin e veprimit dhe një ose disa nga tastet e tjera së bashku"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Kjo do ta fshijë përgjithmonë shkurtoren tënde të personalizuar."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Kjo do të fshijë përgjithmonë të gjitha shkurtoret e tua të personalizuara."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Kërko për shkurtoret"</string> @@ -1463,13 +1464,11 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Po"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Anulo"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Shtyp tastin"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinimi i tasteve është tashmë në përdorim. Provo një tast tjetër."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Kombinimi i tasteve është tashmë në përdorim. Provo një kombinim tjetër."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Shkurtorja nuk mund të caktohet."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> - <!-- no translation found for shortcut_helper_add_shortcut_button_label (7655779534665954910) --> - <skip /> - <!-- no translation found for shortcut_helper_delete_shortcut_button_label (3148773472696137052) --> - <skip /> + <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Shto shkurtore"</string> + <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Fshi shkurtoren"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigo duke përdorur tastierën tënde"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Mëso shkurtoret e tastierës"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigo duke përdorur bllokun me prekje"</string> @@ -1479,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Kthehu prapa"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Shko tek ekrani bazë"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Shiko aplikacionet e fundit"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Ndërro aplikacionet"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"U krye"</string> <string name="gesture_error_title" msgid="469064941635578511">"Provo përsëri!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kthehu prapa"</string> @@ -1496,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Punë e shkëlqyer!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Përfundove gjestin për shikimin e aplikacioneve të fundit."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Për të shikuar aplikacionet e fundit, rrëshqit shpejt lart dhe mbaj shtypur me tre gishta në bllokun me prekje"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Ndërro aplikacionet"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Punë e shkëlqyer!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"E ke përfunduar gjestin e ndërrimit të aplikacioneve."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Shiko të gjitha aplikacionet"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Shtyp tastin e veprimit në tastierë"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Shumë mirë!"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index b7ddd4d7c6d2..70967419276b 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ажурира се"</string> <string name="status_bar_work" msgid="5238641949837091056">"Пословни профил"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Режим рада у авиону"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Нећете чути следећи аларм у <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Сателит, веза је добра"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Сателит, веза је доступна"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Хитна помоћ преко сателита"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Само хитни позиви или хитна помоћ"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"нема сигнала"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"једна црта"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Назад"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Обавештења"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Тастерске пречице"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Промени распоред тастатуре"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"или"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Обриши упит за претрагу"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Тастерске пречице"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системске апликације"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Обављање више задатака истовремено"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Подељени екран"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Унос"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Пречице за апликације"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Актуелна апликација"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Прилагодите пречице"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Желите да уклоните пречицу?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Желите да ресетујете на подразумевано?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Притисните тастер да бисте доделили пречицу"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Да бисте направили ову пречицу, притисните заједно тастер радњи и један или више других тастера"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Овим ћете трајно избрисати прилагођену пречицу."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Тиме ћете трајно избрисати све прилагођене пречице."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Претражите пречице"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Да, ресетуј"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Откажи"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Притисните тастер"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Комбинација тастера се већ користи. Пробајте са другим тастером."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Комбинација тастера се већ користи. Пробајте са другом комбинацијом."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Подешавање пречице није успело."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Додајте пречицу"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Назад"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Иди на почетни екран"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Прикажи недавно коришћене апликације"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Пређи на другу апликацију"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string> <string name="gesture_error_title" msgid="469064941635578511">"Пробајте поново."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Одлично!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Довршили сте покрет за приказивање недавно коришћених апликација."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Да бисте прегледали недавне апликације, превуците нагоре и задржите са три прста на тачпеду"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Пређи на другу апликацију"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Одлично!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Довршили сте покрет за промену апликација."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Прикажи све апликације"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Притисните тастер радњи на тастатури"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Одлично!"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 2d2a94d4e7b2..4e64e5a80d31 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Uppdaterar"</string> <string name="status_bar_work" msgid="5238641949837091056">"Jobbprofil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flygplansläge"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nästa alarm, kl. <xliff:g id="WHEN">%1$s</xliff:g>, kommer inte att höras"</string> <string name="alarm_template" msgid="2234991538018805736">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellit, bra anslutning"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellit, anslutning tillgänglig"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS-larm via satellit"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Endast nödsamtal eller SOS-larm"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ingen signal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"en stapel"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Tillbaka"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Aviseringar"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Kortkommandon"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Byt tangentbordslayout"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"eller"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Rensa sökfråga"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Kortkommandon"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Systemappar"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multikörning"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Delad skärm"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Inmatning"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Genvägar till appar"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuell app"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Anpassa kortkommandon"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Vill du ta bort kortkommandot?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vill du återställa till standardinställningarna?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tryck på tangenten för att tilldela ett kortkommando"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Skapa det här kortkommandot genom att trycka på åtgärdstangenten och en eller flera andra tangenter samtidigt"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Det anpassade kortkommandot raderas permanent."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Alla anpassade genvägar raderas permanent."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sökgenvägar"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ja, återställ"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Avbryt"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tryck på tangenten"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tangentkombinationen används redan. Testa en annan tangent."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Tangentkombinationen används redan. Testa en annan kombination."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Det går inte att ställa in kortkommandot."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Lägg till genväg"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Tillbaka"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Återvänd till startsidan"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Se de senaste apparna"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Byta app"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klar"</string> <string name="gesture_error_title" msgid="469064941635578511">"Försök igen!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tillbaka"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Bra jobbat!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du är klar med rörelsen för att se de senaste apparna."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Svep uppåt på styrplattan med tre fingrar och håll kvar för att se nyligen använda appar"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Byta app"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bra jobbat!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Du har slutfört rörelsen för att byta app"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Visa alla appar"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tryck på åtgärdstangenten på tangentbordet"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bra gjort!"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 424434d182a7..ecba5597e588 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Inasasisha"</string> <string name="status_bar_work" msgid="5238641949837091056">"Wasifu wa kazini"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Hali ya ndegeni"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Hutasikia kengele yako inayofuata ya saa <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"saa <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"siku ya <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Setilaiti, muunganisho thabiti"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Setilaiti, muunganisho unapatikana"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Msaada kupitia Setilaiti"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Simu ya dharura au kipengele cha Msaada kupitia Setilaiti pekee"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"hakuna mtandao"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"upau mmoja"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Nyuma"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Arifa"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Mikato ya Kibodi"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Badili mkao wa kibodi"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"au"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Futa hoja ya utafutaji"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Mikato ya Kibodi"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Programu za mfumo"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Majukumu mengi"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Gawa skrini"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Kifaa cha kuingiza data"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Njia za mikato za programu"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Programu Inayotumika Sasa"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Kuweka mapendeleo ya njia za mkato"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Ungependa kuondoa njia ya mkato?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Ungependa kurejesha njia za mkato chaguomsingi?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Bonyeza kitufe ukabidhi njia ya mkato"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Ili kuanzisha njia hii ya mkato, bonyeza kitufe cha Vitendo na ufunguo mmoja au zaidi kwa pamoja"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Hatua hii itaondoa kabisa njia yako maalum ya mkato."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Hatua hii itafuta kabisa njia zako zote maalum za mkato."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Njia mkato za kutafutia"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ndiyo"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Acha"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Bonyeza kitufe"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tayari unatumia mchanganyiko wa vitufe. Jaribu kitufe kingine."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Tayari unatumia mchanganyiko huu wa vitufe. Jaribu mchanganyiko mwingine."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Haiwezi kuweka njia ya mkato."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Weka njia ya mkato"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Rudi nyuma"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Nenda kwenye ukurasa wa mwanzo"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Angalia programu za hivi majuzi"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Badilisha programu"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Nimemaliza"</string> <string name="gesture_error_title" msgid="469064941635578511">"Jaribu tena!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Rudi nyuma"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Kazi nzuri!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Umekamilisha mafunzo ya mguso wa kuangalia programu za hivi majuzi."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Telezesha vidole vitatu juu na ushikilie kwenye padi yako ya kugusa ili uangalie programu za hivi majuzi"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Badilisha programu"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Kazi nzuri!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Umekamilisha mafunzo kuhusu mguso wa kubadili programu."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Angalia programu zote"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Bonyeza kitufe cha vitendo kwenye kibodi yako"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Vizuri sana!"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index cb340789345e..d6e5be4c1bd5 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"புதுப்பிக்கிறது"</string> <string name="status_bar_work" msgid="5238641949837091056">"பணிக் கணக்கு"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"விமானப் பயன்முறை"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"அடுத்த அலாரத்தை <xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு கேட்க மாட்டீர்கள்"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"சாட்டிலைட், நிலையான இணைப்பு"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"சாட்டிலைட், இணைப்பு கிடைக்கிறது"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"சாட்டிலைட் SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"அவசர அழைப்புகள் அல்லது SOS மட்டும்"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"சிக்னல் இல்லை"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"ஒரு கோடு"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"முந்தையது"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"அறிவிப்புகள்"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"கீபோர்டு ஷார்ட்கட்கள்"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"கீபோர்டு லே அவுட்டை மாற்று"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"அல்லது"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"தேடல் வினவலை அழிக்கும்"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"கீபோர்டு ஷார்ட்கட்கள்"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"சிஸ்டம் ஆப்ஸ்"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"பல வேலைகளைச் செய்தல்"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"திரைப் பிரிப்பு"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"உள்ளீடு"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ஆப்ஸ் ஷார்ட்கட்கள்"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"தற்போதைய ஆப்ஸ்"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ஷார்ட்கட்களைப் பிரத்தியேகமாக்குதல்"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ஷார்ட்கட்டை அகற்றவா?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"மீண்டும் இயல்புநிலைக்கு மீட்டமைக்கவா?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ஷார்ட்கட்டை அமைக்க பட்டனை அழுத்துங்கள்"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"இந்த ஷார்ட்கட்டை உருவாக்க, ஆக்ஷன் பட்டனுடன் ஒன்று அல்லது அதற்கும் மேற்பட்ட பிற பட்டன்களை ஒன்றாக அழுத்துங்கள்"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"இது உங்கள் பிரத்தியேக ஷார்ட்கட்டை நிரந்தரமாக நீக்கும்."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"இது உங்கள் பிரத்தியேக ஷார்ட்கட்கள் அனைத்தையும் நிரந்தரமாக நீக்கும்."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ஷார்ட்கட்களைத் தேடுக"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ஆம். மீட்டமை"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ரத்துசெய்"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"பட்டனை அழுத்துங்கள்"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"பட்டன் சேர்க்கை ஏற்கெனவே பயன்பாட்டில் உள்ளது. வேறொரு பட்டனைப் பயன்படுத்திப் பார்க்கவும்."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"பட்டன் சேர்க்கை ஏற்கெனவே பயன்பாட்டில் உள்ளது. வேறு பட்டன் சேர்க்கையை முயலவும்."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ஷார்ட்கட்டை அமைக்க முடியாது."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"ஷார்ட்கட்டைச் சேர்க்கும்"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"பின்செல்"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"முகப்பிற்குச் செல்"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"சமீபத்திய ஆப்ஸைக் காட்டுதல்"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"ஆப்ஸுக்கிடையில் மாறுங்கள்"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"முடிந்தது"</string> <string name="gesture_error_title" msgid="469064941635578511">"மீண்டும் முயலவும்!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"பின்செல்"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"அருமை!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"சமீபத்தில் பயன்படுத்திய ஆப்ஸுக்கான சைகை பயிற்சியை நிறைவுசெய்துவிட்டீர்கள்."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"சமீபத்திய ஆப்ஸைப் பார்க்க, உங்கள் டச்பேடில் மூன்று விரல்களால் மேல்நோக்கி ஸ்வைப் செய்து பிடிக்கவும்"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ஆப்ஸுக்கிடையில் மாறுங்கள்"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"அருமை!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ஆப்ஸுக்கிடையில் மாறும் சைகைப் பயிற்சியை முடித்துவிட்டீர்கள்."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"அனைத்து ஆப்ஸையும் காட்டு"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"உங்கள் கீபோர்டில் ஆக்ஷன் பட்டனை அழுத்தவும்"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"அருமை!"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 8dac7651ae49..404e5a1308f4 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"అప్డేట్ చేస్తోంది"</string> <string name="status_bar_work" msgid="5238641949837091056">"ఆఫీస్ ప్రొఫైల్"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"విమానం మోడ్"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"మీరు <xliff:g id="WHEN">%1$s</xliff:g> సెట్ చేసిన మీ తర్వాత అలారం మీకు వినిపించదు"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>కి"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>కి"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"శాటిలైట్, కనెక్షన్ బాగుంది"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"శాటిలైట్, కనెక్షన్ అందుబాటులో ఉంది"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"ఎమర్జెన్సీ శాటిలైట్ సహాయం"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"ఎమర్జెన్సీ కాల్స్ లేదా SOS మాత్రమే"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"సిగ్నల్ లేదు"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"సిగ్నల్ ఒక బార్ ఉంది"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"వెనుకకు"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"నోటిఫికేషన్లు"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"కీబోర్డ్ షార్ట్కట్లు"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"కీబోర్డ్ లేఅవుట్ను మార్చండి"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"లేదా"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"సెర్చ్ క్వెరీని క్లియర్ చేయండి"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"కీబోర్డ్ షార్ట్కట్లు"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"సిస్టమ్ యాప్లు"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"మల్టీ-టాస్కింగ్"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"స్ప్లిట్ స్క్రీన్"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ఇన్పుట్"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"యాప్ షార్ట్కట్లు"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ప్రస్తుత యాప్"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"షార్ట్కట్లను అనుకూలంగా మార్చండి"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"షార్ట్కట్ను తీసివేయాలా?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"తిరిగి ఆటోమేటిక్ సెట్టింగ్కు రీసెట్ చేయాలా?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"షార్ట్కట్ను కేటాయించడానికి కీని నొక్కండి"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"ఈ షార్ట్కట్ను క్రియేట్ చేయడానికి, యాక్షన్ కీని, ఒకటి లేదా అంత కంటే ఎక్కువ ఇతర కీలను కలిపి నొక్కండి"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ఇది మీ అనుకూల షార్ట్కట్ను శాశ్వతంగా తొలగిస్తుంది."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ఇది మీ అనుకూల షార్ట్కట్లన్నింటిని శాశ్వతంగా తొలగిస్తుంది."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"షార్ట్కట్లను వెతకండి"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"అవును, రీసెట్ చేయాలి"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"రద్దు చేయండి"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"కీని నొక్కండి"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"కీ కాంబినేషన్ ఇప్పటికే వినియోగంలో ఉంది. వేరొక కీని ట్రై చేయండి."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"కీ కాంబినేషన్ ఇప్పటికే వినియోగంలో ఉంది. మరొక కాంబినేషన్ను ట్రై చేయండి."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"షార్ట్కట్ను సెట్ చేయడం సాధ్యం కాదు."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"షార్ట్కట్ను జోడించండి"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"వెనుకకు వెళ్లండి"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"మొదటి ట్యాబ్కు వెళ్లండి"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ఇటీవలి యాప్లను చూడండి"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"యాప్ల మధ్య మారండి"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"పూర్తయింది"</string> <string name="gesture_error_title" msgid="469064941635578511">"మళ్లీ ట్రై చేయండి!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"వెనుకకు"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"చక్కగా పూర్తి చేశారు!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ఇటీవలి యాప్లను చూడడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్ను మీరు పూర్తి చేశారు."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ఇటీవలి యాప్లను చూడటానికి, మీ టచ్ప్యాడ్లో మూడు వేళ్లను ఉపయోగించి పైకి స్వైప్ చేసి, హోల్డ్ చేయండి"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"యాప్ల మధ్య మారండి"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"చక్కగా పూర్తి చేశారు!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"మీరు యాప్ల మధ్య మారేందుకు సంజ్ఞను పూర్తి చేశారు."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"అన్ని యాప్లను చూడండి"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"మీ కీబోర్డ్లో యాక్షన్ కీని నొక్కండి"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"చక్కగా చేశారు!"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index cd111fd54d02..c67852bd826a 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"กำลังอัปเดต"</string> <string name="status_bar_work" msgid="5238641949837091056">"โปรไฟล์งาน"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"โหมดบนเครื่องบิน"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"คุณจะไม่ได้ยินเสียงปลุกครั้งถัดไปในเวลา <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"เวลา <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ในวันที่ <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ดาวเทียม, การเชื่อมต่อดี"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"ดาวเทียม, การเชื่อมต่อที่พร้อมใช้งาน"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"SOS ดาวเทียม"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"โทรฉุกเฉินหรือ SOS เท่านั้น"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ไม่มีสัญญาณ"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"1 ขีด"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"กลับ"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"การแจ้งเตือน"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"แป้นพิมพ์ลัด"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"สลับรูปแบบแป้นพิมพ์"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"หรือ"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ล้างคำค้นหา"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"แป้นพิมพ์ลัด"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"แอประบบ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"การทํางานหลายอย่างพร้อมกัน"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"แยกหน้าจอ"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"อินพุต"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"แป้นพิมพ์ลัดของแอป"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"แอปปัจจุบัน"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"ปรับแต่งแป้นพิมพ์ลัด"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"นำแป้นพิมพ์ลัดออกใช่ไหม"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"รีเซ็ตกลับเป็นค่าเริ่มต้นไหม"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"กดแป้นเพื่อกำหนดแป้นพิมพ์ลัด"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"หากต้องการสร้างแป้นพิมพ์ลัดนี้ ให้กดปุ่มดำเนินการและปุ่มอื่นๆ อย่างน้อย 1 ปุ่มพร้อมกัน"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"การดำเนินการนี้จะลบแป้นพิมพ์ลัดที่กำหนดเองอย่างถาวร"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"การดำเนินการนี้จะลบแป้นพิมพ์ลัดที่กำหนดเองทั้งหมดอย่างถาวร"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ค้นหาแป้นพิมพ์ลัด"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ใช่ รีเซ็ต"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ยกเลิก"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"กดแป้น"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"มีการใช้แป้นที่กดร่วมกันนี้แล้ว โปรดลองใช้แป้นอื่น"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"มีการใช้แป้นที่กดร่วมกันนี้แล้ว โปรดลองใช้ชุดค่าผสมอื่น"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"ตั้งค่าแป้นพิมพ์ลัดไม่ได้"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"เพิ่มทางลัด"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"ย้อนกลับ"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ไปที่หน้าแรก"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"ดูแอปล่าสุด"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"เปลี่ยนแอป"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"เสร็จสิ้น"</string> <string name="gesture_error_title" msgid="469064941635578511">"ลองอีกครั้งนะ"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ย้อนกลับ"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"เยี่ยมมาก"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"คุณทำท่าทางสัมผัสเพื่อดูแอปล่าสุดสำเร็จแล้ว"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"หากต้องการดูแอปล่าสุด ให้ใช้ 3 นิ้วปัดขึ้นแล้วค้างไว้บนทัชแพด"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"เปลี่ยนแอป"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"เก่งมาก"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"คุณทำท่าทางสัมผัสเพื่อสลับแอปเสร็จแล้ว"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ดูแอปทั้งหมด"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"กดปุ่มดำเนินการบนแป้นพิมพ์"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ยอดเยี่ยม"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 3c5448e20664..cf2b2f043963 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ina-update"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profile sa trabaho"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Airplane mode"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Hindi mo maririnig ang iyong susunod na alarm ng <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"ng <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"sa <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Satellite, malakas ang koneksyon"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Satellite, may koneksyon"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Satellite SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Mga emergency na tawag o SOS lang"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"walang signal"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"isang bar"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Bumalik"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Mga Notification"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Mga Keyboard Shortcut"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Magpalit ng layout ng keyboard"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"o"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"I-clear ang query sa paghahanap"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Mga Keyboard Shortcut"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Mga system app"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Pag-multitask"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Split screen"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Mga shortcut ng app"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Kasalukuyang App"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"I-customize ang mga shortcut"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Alisin ang shortcut?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"I-reset pabalik sa default?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pindutin ang key para magtalaga ng shortcut"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Para gawin ang shortcut na ito, pindutin nang magkasabay ang Action key at isa o higit pang key"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Permanente nitong ide-delete ang iyong custom na shortcut."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Permanente nitong ide-delete ang lahat ng iyong custom na shortcut."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Mga shortcut ng paghahanap"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Oo, i-reset"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Kanselahin"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pindutin ang key"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ginagamit na ang kumbinasyon ng key. Sumubok ng ibang key."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Ginagamit na ang kumbinasyon ng key. Sumubok ng ibang kumbinasyon."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Hindi maitakda ang shortcut."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Maglagay ng shortcut"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Bumalik"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Pumunta sa home"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Tingnan ang mga kamakailang app"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Lumipat ng app"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Tapos na"</string> <string name="gesture_error_title" msgid="469064941635578511">"Subukan ulit!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Bumalik"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Magaling!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Nakumpleto mo ang galaw sa pag-view ng mga kamakailang app."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Para tingnan ang mga kamakailang app, mag-swipe pataas at i-hold gamit ang tatlong daliri sa iyong touchpad"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Lumipat ng app"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Magaling!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Nakumpleto mo na ang galaw para magpalipat-lipat sa mga app."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Tingnan ang lahat ng app"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pindutin ang action key sa iyong keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Magaling!"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 61ed4e54209b..8cd9eb36d180 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Güncelleniyor"</string> <string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Uçak modu"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> olarak ayarlanmış bir sonraki alarmınızı duymayacaksınız"</string> <string name="alarm_template" msgid="2234991538018805736">"saat: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"gün ve saat: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Uydu, bağlantı güçlü"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Uydu, bağlantı mevcut"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Acil Uydu Bağlantısı"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Yalnızca acil durum aramaları veya acil yardım"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"sinyal yok"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"tek çubuk"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Geri"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Bildirimler"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Klavye Kısayolları"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Klavye düzenini değiştir"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"veya"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Arama sorgusunu temizle"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Klavye Kısayolları"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistem uygulamaları"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Çoklu görev"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Bölünmüş ekran"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Giriş"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Uygulama kısayolları"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Mevcut Uygulama"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Kısayolları özelleştirin"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Kısayol kaldırılsın mı?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Varsayılan kısayollara sıfırlansın mı?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Kısayol atamak için tuşa basın"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Bu kısayolu oluşturmak için Eylem tuşuna ve bir veya daha fazla başka tuşa aynı anda basın"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Bu işlem, özel kısayolunuzu kalıcı olarak siler."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Bu işlem, tüm özel kısayollarınızı kalıcı olarak siler."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Kısayollarda ara"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sıfırla"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"İptal"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tuşa basın"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tuş kombinasyonu zaten kullanılıyor. Başka bir tuş deneyin."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Tuş kombinasyonu zaten kullanılıyor. Başka bir tuş kombinasyonu deneyin."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Kısayol ayarlanamıyor."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Kısayol ekle"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Geri dön"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Ana sayfaya git"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Son uygulamaları görüntüle"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Uygulamalar arasında geçiş yapma"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Bitti"</string> <string name="gesture_error_title" msgid="469064941635578511">"Tekrar deneyin."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri dön"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Tebrikler!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Son uygulamaları görüntüleme hareketini tamamladınız."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Son kullanılan uygulamaları görüntülemek için dokunmatik alanda üç parmağınızla yukarı kaydırıp basılı tutun"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Uygulamalar arasında geçiş yapma"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Tebrikler!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Uygulamalar arasında geçiş yapma hareketini tamamladınız."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Tüm uygulamaları göster"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Klavyenizde eylem tuşuna basın"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Tebrikler!"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 778b25bf4651..bd877f3a4c7c 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Оновлення"</string> <string name="status_bar_work" msgid="5238641949837091056">"Робочий профіль"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Режим польоту"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Наступний сигнал о <xliff:g id="WHEN">%1$s</xliff:g> не пролунає"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Хороше з’єднання із супутником"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Доступне з’єднання із супутником"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Супутниковий сигнал SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Лише екстрені виклики або сигнал SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"немає сигналу"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"одна смужка сигналу"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Назад"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Сповіщення"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Комбінації клавіш"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Змінити розкладку клавіатури"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"або"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Очистити пошуковий запит"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Комбінації клавіш"</string> @@ -1290,7 +1290,7 @@ <string name="accessibility_enter_hint" msgid="2617864063504824834">"відкрити пристрій"</string> <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Щоб відкрити, використайте відбиток пальця"</string> <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Пройдіть автентифікацію. Для цього торкніться сканера відбитків пальців."</string> - <string name="ongoing_call_content_description" msgid="6394763878322348560">"Поточний виклик"</string> + <string name="ongoing_call_content_description" msgid="6394763878322348560">"Поточний дзвінок"</string> <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобільний трафік"</string> <string name="mobile_data_connection_active" msgid="944490013299018227">"Підключено"</string> <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Тимчасово з’єднано"</string> @@ -1432,16 +1432,17 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системні додатки"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Багатозадачність"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Розділити екран"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Введення"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Комбінації клавіш для додатків"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Поточний додаток"</string> <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Доступність"</string> <string name="shortcut_helper_title" msgid="8567500639300970049">"Комбінації клавіш"</string> - <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) --> - <skip /> + <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Налаштуйте комбінації клавіш"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Видалити комбінацію клавіш?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Відновити комбінації клавіш за умовчанням?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Натисніть клавішу, щоб призначити комбінацію клавіш"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Щоб створити цю комбінацію, одночасно натисніть клавішу дії і одну чи кілька інших клавіш"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Вашу власну комбінацію клавіш буде видалено назавжди."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Усі ваші власні комбінації клавіш буде видалено назавжди."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пошук комбінацій клавіш"</string> @@ -1463,13 +1464,11 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Так, відновити"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Скасувати"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Натисніть клавішу"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Комбінація клавіш уже використовується. Спробуйте іншу клавішу."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Комбінація клавіш уже використовується. Спробуйте іншу."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Не вдалося встановити комбінацію клавіш."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> - <!-- no translation found for shortcut_helper_add_shortcut_button_label (7655779534665954910) --> - <skip /> - <!-- no translation found for shortcut_helper_delete_shortcut_button_label (3148773472696137052) --> - <skip /> + <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Додати комбінацію клавіш"</string> + <string name="shortcut_helper_delete_shortcut_button_label" msgid="3148773472696137052">"Видалити комбінацію клавіш"</string> <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Навігація за допомогою клавіатури"</string> <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Дізнайтеся більше про комбінації клавіш"</string> <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Навігація за допомогою сенсорної панелі"</string> @@ -1479,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Назад"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Перейти на головний екран"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Переглянути нещодавні додатки"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Перемикання між додатками"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string> <string name="gesture_error_title" msgid="469064941635578511">"Спробуйте ще"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string> @@ -1496,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Чудово!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ви виконали жест для перегляду нещодавно відкритих додатків."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Щоб переглянути останні додатки, проведіть трьома пальцями вгору й утримуйте їх на сенсорній панелі"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Перемикання між додатками"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Чудово!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ви виконали жест перемикання додатків."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Переглянути всі додатки"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Натисніть клавішу дії на клавіатурі"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Чудово!"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 2f3e6f4bcfe8..d3900f2be29f 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"اپ ڈیٹ ہو رہا ہے"</string> <string name="status_bar_work" msgid="5238641949837091056">"دفتری پروفائل"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ہوائی جہاز وضع"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"آپ کو <xliff:g id="WHEN">%1$s</xliff:g> بجے اپنا اگلا الارم سنائی نہیں دے گا"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> بجے"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> بجے"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"سیٹلائٹ، کنکشن اچھا ہے"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"سیٹلائٹ، کنکشن دستیاب ہے"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"سیٹلائٹ SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"صرف ایمرجنسی کالز یا SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>، <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>۔"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"کوئی سگنل نہیں"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"ایک بار"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"پیچھے"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"اطلاعات"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"کی بورڈ شارٹ کٹس"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"کی بورڈ لے آؤٹ سوئچ کریں"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"یا"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"تلاش کا استفسار صاف کریں"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"کی بورڈ شارٹ کٹس"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"سسٹم ایپس"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ملٹی ٹاسکنگ"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"اسپلٹ اسکرین"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ان پٹ"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ایپ شارٹ کٹس"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"موجودہ ایپ"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"شارٹ کٹس کو حسب ضرورت بنائیں"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"شارٹ کٹ ہٹائیں؟"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ڈیفالٹ پر واپس ری سیٹ کریں؟"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"شارٹ کٹ تفویض کرنے کے لیے کلید کو دبائیں"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"یہ شارٹ کٹ تخلیق کرنے کے لیے، ایکشن کلید اور ایک یا زیادہ دوسری کلیدوں کو ایک ساتھ دبائیں"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"اس سے آپ کا حسب ضرورت شارٹ کٹ مستقل طور پر حذف ہو جائے گا۔"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"اس سے آپ کے تمام حسب ضرورت شارٹ کٹس مستقل طور پر حذف ہو جائیں گے۔"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"تلاش کے شارٹ کٹس"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ہاں، ری سیٹ کریں"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"منسوخ کریں"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"کلید کو دبائیں"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"کلیدی مجموعہ پہلے سے استعمال میں ہے۔ دوسری کلید آزمائیں۔"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"کلیدی مجموعہ پہلے سے استعمال میں ہے۔ دوسرا مجموعہ آزمائیں۔"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"شارٹ کٹ سیٹ نہیں کیا جا سکتا۔"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"شارٹ کٹ شامل کریں"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"واپس جائیں"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"ہوم پر جائیں"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"حالیہ ایپس دیکھیں"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"ایپس سوئچ کریں"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ہو گیا"</string> <string name="gesture_error_title" msgid="469064941635578511">"دوبارہ کوشش کریں!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"واپس جائیں"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"بہترین!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"آپ نے حالیہ ایپس دیکھیں کا اشارہ مکمل کر لیا ہے۔"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"حالیہ ایپس دیکھنے کے لیے، اپنے ٹچ پیڈ پر تین انگلیوں کی مدد سے اوپر کی طرف سوائپ کریں اور دبائے رکھیں"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ایپس سوئچ کریں"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"بہترین!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"آپ نے ایپس کے مابین سوئچ کرنے کا اشارہ مکمل کر لیا۔"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"سبھی ایپس دیکھیں"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"اپنے کی بورڈ پر ایکشن کلید دبائیں"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"بہت خوب!"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 23137bd9898c..7006abb34b99 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Yangilanmoqda"</string> <string name="status_bar_work" msgid="5238641949837091056">"Ish profili"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Parvoz rejimi"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Keyingi signal (<xliff:g id="WHEN">%1$s</xliff:g>) chalinmaydi"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Sputnik, aloqa sifati yaxshi"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Sputnik, aloqa mavjud"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Sputnik SOS"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Faqat favqulodda chaqiruvlar yoki SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"signal yoʻq"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"bitta ustun"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Orqaga"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Bildirishnomalar"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Tezkor tugmalar"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Klaviatura terilmasini almashtirish"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"yoki"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Qidiruv soʻrovini tozalash"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tezkor tugmalar"</string> @@ -1432,16 +1432,17 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Tizim ilovalari"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multi-vazifalilik"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ekranni ikkiga ajratish"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Kiritish"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Ilova yorliqlari"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Joriy ilova"</string> <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Qulayliklar"</string> <string name="shortcut_helper_title" msgid="8567500639300970049">"Tezkor tugmalar"</string> - <!-- no translation found for shortcut_helper_customize_mode_title (8327297960035006036) --> - <skip /> + <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Yorliqlarni moslash"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Tezkor tugma olib tashlansinmi?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Asliga qaytarilsinmi?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tezkor tugma sozlash uchun tugmani bosing"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Bu tezkor tugmani yaratish uchun Amal tugmasi va bir yoki bir nechta tugmalarni birgalikda bosing"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Bunda maxsus tezkor tugma butunlay oʻchirib tashlanadi."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Bunda barcha maxsus yorliqlaringiz butunlay oʻchirib tashlanadi."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tezkor tugmalar qidiruvi"</string> @@ -1463,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ha, asliga qaytarilsin"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Bekor qilish"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tugmani bosing"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Bu tugmalar birikmasi band. Boshqasini ishlating."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Bu tugmalar birikmasi band. Boshqa birikmani sinang."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Buyruq sozlanmadi."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Yorliq yaratish"</string> @@ -1477,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Orqaga"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Boshiga qaytish"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Oxirgi ilovalarni koʻrish"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Ilovalarni almashtirish"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Tayyor"</string> <string name="gesture_error_title" msgid="469064941635578511">"Qayta urining!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Orqaga qaytish"</string> @@ -1494,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Barakalla!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Oxirgi ilovalarni koʻrish ishorasini tugalladingiz."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Oxirgi ochilgan ilovalarni koʻrish uchun sensorli panelda uchta barmoq bilan tepega surib, ushlab turing"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Ilovalarni almashtirish"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Barakalla!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ilovalarni almashtirish darsini tamomladingiz."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Barcha ilovalarni koʻrish"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Klaviaturadagi amal tugmasini bosing"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Barakalla!"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 3b4b132698f3..18857426db84 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Đang cập nhật"</string> <string name="status_bar_work" msgid="5238641949837091056">"Hồ sơ công việc"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Chế độ trên máy bay"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Bạn sẽ không nghe thấy chuông báo tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình"</string> <string name="alarm_template" msgid="2234991538018805736">"lúc <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"vào <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Kết nối vệ tinh tốt"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Hiện có kết nối vệ tinh"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Liên lạc khẩn cấp qua vệ tinh"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Chỉ cuộc gọi khẩn cấp hoặc SOS"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"không có tín hiệu"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"1 vạch"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Quay lại"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Thông báo"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Phím tắt"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Chuyển đổi bố cục bàn phím"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"hoặc"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Xoá cụm từ tìm kiếm"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Phím tắt"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Ứng dụng hệ thống"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Đa nhiệm"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Chia đôi màn hình"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Phương thức nhập"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Phím tắt cho ứng dụng"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Ứng dụng hiện tại"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Tuỳ chỉnh phím tắt"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Xoá phím tắt?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Đặt lại về phím tắt mặc định?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Nhấn phím để chỉ định phím tắt"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Để tạo phím tắt này, hãy nhấn tổ hợp phím Hành động và một hoặc nhiều phím khác"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Thao tác này sẽ xoá vĩnh viễn phím tắt tuỳ chỉnh của bạn."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Thao tác này sẽ xoá vĩnh viễn mọi phím tắt tuỳ chỉnh của bạn."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tìm phím tắt"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Có, đặt lại"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Huỷ"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Nhấn phím"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Tổ hợp phím đã được sử dụng. Hãy thử một phím khác."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Tổ hợp phím đã được sử dụng. Hãy thử một tổ hợp khác."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Không đặt được lối tắt."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Thêm phím tắt"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Quay lại"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Chuyển đến màn hình chính"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Xem các ứng dụng gần đây"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Chuyển đổi ứng dụng"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Xong"</string> <string name="gesture_error_title" msgid="469064941635578511">"Hãy thử lại!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Quay lại"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Tuyệt vời!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Bạn đã hoàn tất cử chỉ xem ứng dụng gần đây."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Để xem các ứng dụng gần đây, hãy dùng 3 ngón tay vuốt lên và giữ trên bàn di chuột"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Chuyển đổi ứng dụng"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Tuyệt vời!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Bạn đã thực hiện xong cử chỉ chuyển đổi ứng dụng."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Xem tất cả các ứng dụng"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Nhấn phím hành động trên bàn phím"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Rất tốt!"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index e66048e8022a..53c825baab02 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -83,7 +83,7 @@ <string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"必须先解锁设备,然后才能保存屏幕截图"</string> <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"请再次尝试截屏"</string> <string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"无法保存屏幕截图"</string> - <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"此应用或您所在的单位不允许进行屏幕截图"</string> + <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"此应用或您所在的组织不允许截屏"</string> <string name="screenshot_blocked_by_admin" msgid="5486757604822795797">"您的 IT 管理员已禁止截取屏幕截图"</string> <string name="screenshot_edit_label" msgid="8754981973544133050">"编辑"</string> <string name="screenshot_edit_description" msgid="3333092254706788906">"编辑屏幕截图"</string> @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"正在更新"</string> <string name="status_bar_work" msgid="5238641949837091056">"工作资料"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"飞行模式"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"您在<xliff:g id="WHEN">%1$s</xliff:g>将不会听到下次闹钟响铃"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"卫星,连接质量良好"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"卫星,可连接"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"卫星紧急呼救"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"仅限紧急呼叫或紧急求救"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>,<xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>。"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"无信号"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"信号强度为一格"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"返回"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"通知"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"键盘快捷键"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"切换键盘布局"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"或"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"清除搜索查询"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"键盘快捷键"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"系统应用"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"多任务处理"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"分屏"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"输入"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"应用快捷键"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"当前应用"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"自定义快捷方式"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"要移除快捷键吗?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"要重置为默认快捷键吗?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"按下按键即可指定快捷键"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"若要创建此快捷方式,请同时按下快捷操作按键以及一个或多个其他键"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"此操作会永久删除您的自定义快捷键。"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"此操作会永久删除您的所有自定义快捷键。"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜索快捷键"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"是,重置"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"取消"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"按下按键"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"按键组合已被使用,请尝试使用其他按键。"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"按键组合已被使用,请尝试其他组合。"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"无法设置快捷方式。"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"添加快捷方式"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"返回"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"前往主屏幕"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"查看最近用过的应用"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"切换应用"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string> <string name="gesture_error_title" msgid="469064941635578511">"再试一次!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"太棒了!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"您已完成“查看最近用过的应用”的手势教程。"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"如需查看最近用过的应用,请用三根手指在触控板上向上滑动并按住"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"切换应用"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"太棒了!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"您完成了应用切换手势教程。"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"查看所有应用"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按键盘上的快捷操作按键"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"非常棒!"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index f9631f267948..aa539d699378 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"正在更新"</string> <string name="status_bar_work" msgid="5238641949837091056">"工作設定檔"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"飛行模式"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"你不會<xliff:g id="WHEN">%1$s</xliff:g>聽到鬧鐘"</string> <string name="alarm_template" msgid="2234991538018805736">"在 <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"在<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"衛星,連線質素好"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"衛星,可以連線"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"緊急衛星連接"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"只限緊急電話或緊急求救"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>,<xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>。"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"無訊號"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"一格"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"返回"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"通知"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"鍵盤快速鍵"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"切換鍵盤配置"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"或"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"清除搜尋查詢"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"鍵盤快速鍵"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"系統應用程式"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"多工處理"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"分割螢幕"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"輸入"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"應用程式捷徑"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"目前的應用程式"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"自訂快速鍵"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"要移除快速鍵嗎?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"要重設至預設捷徑嗎?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"按鍵即可指派快速鍵"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"如要建立此快速鍵,請同時按下 Action 鍵及另外一個或多個鍵"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"這將永久刪除你的自訂快速鍵。"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"這將永久刪除你的所有自訂捷徑。"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"是,請重設"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"取消"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"按鍵"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"此按鍵組合已在使用,請改用其他按鍵。"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"此按鍵組合已在使用,請改用其他組合。"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"無法設定快速鍵。"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"新增捷徑"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"返回"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"返回主畫面"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"查看最近使用的應用程式"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"切換應用程式"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string> <string name="gesture_error_title" msgid="469064941635578511">"請再試一次!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"做得好!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"你已完成「查看最近使用的應用程式」手勢的教學課程。"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"如要查看最近使用的應用程式,請用三隻手指在觸控板上向上滑動並按住"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"切換應用程式"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"做得好!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"你已完成「應用程式切換手勢」的教學課程。"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"查看所有應用程式"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按下鍵盤上的快捷操作鍵"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"做得好!"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 4394dd9a0bd7..2d6ac8d43442 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -750,6 +750,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"更新中"</string> <string name="status_bar_work" msgid="5238641949837091056">"工作資料夾"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"飛航模式"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"你不會聽到下一個<xliff:g id="WHEN">%1$s</xliff:g> 的鬧鐘"</string> <string name="alarm_template" msgid="2234991538018805736">"於<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"於<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -759,8 +761,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"衛星,連線品質良好"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"衛星,可連線"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"緊急衛星連線"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"僅限緊急電話或需要求救的情況"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>,<xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>。"</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"沒有訊號"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"訊號強度一格"</string> @@ -857,7 +858,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"返回"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"通知"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"鍵盤快速鍵"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"切換鍵盤配置"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"或"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"清除搜尋查詢"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"鍵盤快速鍵"</string> @@ -1432,6 +1432,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"系統應用程式"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"多工處理"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"分割畫面"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"輸入"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"應用程式捷徑"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"目前的應用程式"</string> @@ -1440,7 +1442,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"自訂快速鍵"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"要移除快速鍵嗎?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"要重設為預設值嗎?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"按下按鍵即可指派快速鍵"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"如要建立這個快速鍵,請同時按下快捷操作鍵和一或多個其他鍵"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"這項操作會永久刪除自訂快速鍵。"</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"這麼做會永久刪除所有快速鍵。"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string> @@ -1462,7 +1464,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"是,請重設"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"取消"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"按下按鍵"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"按鍵組合重複,請改用其他按鍵。"</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"這組按鍵已在使用中,請試試其他組合。"</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"無法設定捷徑。"</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"新增快速鍵"</string> @@ -1476,6 +1478,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"返回"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"返回主畫面"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"查看最近使用的應用程式"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"切換應用程式"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string> <string name="gesture_error_title" msgid="469064941635578511">"請再試一次!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string> @@ -1493,6 +1496,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"太棒了!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"你已完成「查看最近使用的應用程式」手勢教學課程。"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"如要查看最近使用的應用程式,請在觸控板上用三指向上滑動並按住"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"切換應用程式"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"太棒了!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"你已完成應用程式切換手勢的教學課程。"</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"查看所有應用程式"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按下鍵盤上的快捷操作鍵"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"非常好!"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index f7f4bcfcdc83..a210ca37214f 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -752,6 +752,8 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Iyabuyekeza"</string> <string name="status_bar_work" msgid="5238641949837091056">"Iphrofayela yomsebenzi"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Imodi yendiza"</string> + <!-- no translation found for status_bar_supervision (6735015942701134125) --> + <skip /> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ngeke uzwe i-alamu yakho elandelayo ngo-<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"ngo-<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"nge-<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -761,8 +763,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Isethelayithi, uxhumano oluhle"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Isethelayithi, uxhumano luyatholakala"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Isethelayithi yokuxhumana ngezimo eziphuthumayo"</string> - <!-- no translation found for satellite_emergency_only_carrier_text (9103913890116841786) --> - <skip /> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"Izingcingo eziphuthumayo noma i-SOS kuphela"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"ayikho isignali"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"ibha eyodwa"</string> @@ -859,7 +860,6 @@ <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"Emuva"</string> <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Izaziso"</string> <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Izinqamulelo Zekhibhodi"</string> - <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Shintsha isakhiwo sekhibhodi"</string> <string name="keyboard_shortcut_join" msgid="3578314570034512676">"noma"</string> <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Sula umbuzo wosesho"</string> <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Izinqamuleli Zekhibhodi"</string> @@ -1434,6 +1434,8 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Ama-app esistimu"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Ukwenza imisebenzi eminingi"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Hlukanisa isikrini"</string> + <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> + <skip /> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Okokufaka"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Izinqamuleli Zohlelo lokusebenza"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"I-App yamanje"</string> @@ -1442,7 +1444,7 @@ <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Qamba ngokwabahlinzekelwayo izinqamuleli"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Susa isinqamuleli?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Setha kabusha ubuyele kokuzenzakalelayo?"</string> - <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Cindezela ukhiye ukuze unikeze isinqamuleli"</string> + <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Ukuze usungule lesi sinqamuleli, cindezela ukhiye Wesenzo kanye nokhiye owodwa noma ngaphezulu ndawonye"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Lokhu kuzosula isinqamuleli sakho somuntu ngamunye unomphela."</string> <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Lokhu kuzosula unomphela zonke izinqamuleli zakho zangokwezifiso."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sesha izinqamuleli"</string> @@ -1464,7 +1466,7 @@ <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Yebo, setha kabusha"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Khansela"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Cindezela ukhiye"</string> - <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Inhlanganisela yokhiye isiyasetshenziswa kakade. Zama omunye ukhiye."</string> + <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="3325858369539848162">"Inhlanganisela yokhiye isiyasetshenziswa kakade. Zama enye inhlanganisela."</string> <string name="shortcut_customizer_generic_error_message" msgid="3128454624049722741">"Isinqamuleli asikwazi ukusethwa."</string> <string name="shortcut_helper_plus_symbol" msgid="4534843157353732011">"+"</string> <string name="shortcut_helper_add_shortcut_button_label" msgid="7655779534665954910">"Faka isinqamuleli"</string> @@ -1478,6 +1480,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"Iya emuva"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"Iya ekhasini lokuqala"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"Buka ama-app akamuva"</string> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"Shintsha ama-app"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Kwenziwe"</string> <string name="gesture_error_title" msgid="469064941635578511">"Zama futhi!"</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Buyela emuva"</string> @@ -1495,6 +1498,13 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Umsebenzi omuhle!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Uqedele ukubuka ukuthinta kwama-app akamuva."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Ukuze ubuke ama-app akamuva, swayiphela phezulu futhi ubambe usebenzisa iminwe emithathu kuphedi yakho yokuthinta"</string> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Shintsha ama-app"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <skip /> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Umsebenzi omuhle!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ukuqedile ukuthinta kokushintsha ama-app."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Buka wonke ama-app"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Cindezela inkinobho yokufinyelela kukhibhodi yakho"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Wenze kahle!"</string> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index d2b7d0b90c43..36ede64f91d9 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -31,8 +31,14 @@ <!-- The dark background color behind the shade --> <color name="shade_scrim_background_dark">@androidprv:color/system_under_surface_light</color> - <!-- Colors for notification shade/scrim --> - <color name="shade_panel">@android:color/system_accent1_800</color> + <!-- Base colors for notification shade/scrim, the alpha component is adjusted programmatically + to match the spec --> + <color name="shade_panel">@android:color/system_accent1_900</color> + <color name="surface_effect_0">@android:color/system_accent1_100</color> + + <!-- todo(b/388891904) Remove updated color references once they are available. --> + <color name="shade_panel_base">@color/shade_panel</color> + <color name="notification_scrim_base">@color/surface_effect_0</color> <!-- The color of the background in the separated list of the Global Actions menu --> <color name="global_actions_separated_background">#F5F5F5</color> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index f9904e336f24..8a0ffb90bf09 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -2057,6 +2057,8 @@ <dimen name="dream_overlay_status_bar_ambient_text_shadow_dy">0.5dp</dimen> <dimen name="dream_overlay_status_bar_ambient_text_shadow_radius">3dp</dimen> <dimen name="dream_overlay_icon_inset_dimen">0dp</dimen> + <dimen name="dream_overlay_icon_shadow_radius">1dp</dimen> + <dimen name="dream_overlay_icon_ambient_shadow_radius">2dp</dimen> <!-- Default device corner radius, used for assist UI --> <dimen name="config_rounded_mask_size">0px</dimen> diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index c06b0784092c..dc089e707ca3 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -218,6 +218,7 @@ <item type="id" name="accessibility_actions_view" /> <item type="id" name="ambient_indication_container" /> <item type="id" name="aod_notification_icon_container" /> + <item type="id" name="aod_promoted_notification_frame" /> <item type="id" name="burn_in_layer" /> <item type="id" name="burn_in_layer_empty_view" /> <item type="id" name="communal_tutorial_indicator" /> @@ -291,4 +292,5 @@ <item type="id" name="brightness_dialog_slider" /> + <item type="id" name="aod_promoted_notification_view_updater_tag" /> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 4d0e4600bec9..1e52e9f135cb 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1351,14 +1351,14 @@ <string name="communal_widgets_disclaimer_text">To open an app using a widget, you\u2019ll need to verify it\u2019s you. Also, keep in mind that anyone can view them, even when your tablet\u2019s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here.</string> <!-- Button for user to verify they understand the information presented. [CHAR LIMIT=50] --> <string name="communal_widgets_disclaimer_button">Got it</string> - <!-- Label for a lock screen affordance to show widgets on the lock screen. [CHAR LIMIT=20] --> - <string name="glanceable_hub_lockscreen_affordance_label">Widgets</string> - <!-- Text explaining why the lock screen affordance to show widgets on the lockscreen is disabled and how to enable the affordance in settings. [CHAR LIMIT=NONE] --> - <string name="glanceable_hub_lockscreen_affordance_disabled_text">To add the \"Widgets\" shortcut, make sure \"Show widgets on lock screen\" is enabled in settings.</string> - <!-- Label for a button used to open Settings in order to enable showing widgets on the lock screen. [CHAR LIMIT=NONE] --> - <string name="glanceable_hub_lockscreen_affordance_action_button_label">Settings</string> <!-- Content description for a "show screensaver" button on glanceable hub. [CHAR LIMIT=NONE] --> <string name="accessibility_glanceable_hub_to_dream_button">Show screensaver button</string> + <!-- Title shown in hub onboarding bottom sheet. [CHAR LIMIT=50] --> + <string name="hub_onboarding_bottom_sheet_title">Explore hub mode</string> + <!-- Information about communal hub shown in the onboarding bottom sheet. [CHAR LIMIT=NONE] --> + <string name="hub_onboarding_bottom_sheet_text">Access your favorite widgets and screen savers while charging.</string> + <!-- Hub onboarding bottom sheet action button title. [CHAR LIMIT=NONE] --> + <string name="hub_onboarding_bottom_sheet_action_button">Let\u2019s go</string> <!-- Related to user switcher --><skip/> @@ -3779,6 +3779,11 @@ that shows the user which keyboard shortcuts they can use. The "Split screen" shortcuts are for example "Move current app to left split". [CHAR LIMIT=NONE] --> <string name="shortcutHelper_category_split_screen">Split screen</string> + <!-- Title of the keyboard shortcut helper category "Accessibility". This category contains shortcuts + for android accessibility and disability inclusion features such as screen readers, voice control, + switch access, talkback, etc. The helper is a component that shows the user which keyboard + shortcuts they can use. [CHAR LIMIT=NONE] --> + <string name="shortcutHelper_category_accessibility">Accessibility</string> <!-- Title of the keyboard shortcut helper category "Input". The helper is a component that shows the user which keyboard shortcuts they can use. The "Input" shortcuts are the ones provided by the keyboard. Examples are "Access emoji" or "Switch to next language" diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 08891aa65417..b0d9bed05e27 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -430,6 +430,7 @@ <style name="Theme.SystemUI.MediaProjectionAppSelector" parent="@*android:style/Theme.DeviceDefault.Chooser"> + <item name="android:colorBackground">@*android:color/materialColorSurfaceContainer</item> </style> <!-- Standard animations for hiding and showing the status bar. --> diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 9b852df88604..71b622aa0608 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -61,8 +61,6 @@ import com.android.systemui.plugins.clocks.ClockTickRate import com.android.systemui.plugins.clocks.WeatherData import com.android.systemui.plugins.clocks.ZenData import com.android.systemui.plugins.clocks.ZenData.ZenMode -import com.android.systemui.power.domain.interactor.PowerInteractor -import com.android.systemui.power.shared.model.ScreenPowerState import com.android.systemui.res.R as SysuiR import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.settings.UserTracker @@ -108,7 +106,6 @@ constructor( private val zenModeController: ZenModeController, private val zenModeInteractor: ZenModeInteractor, private val userTracker: UserTracker, - private val powerInteractor: PowerInteractor, ) { var loggers = listOf( @@ -380,12 +377,12 @@ constructor( override fun onTimeChanged() { refreshTime() } - } - private fun refreshTime() { - clock?.smallClock?.events?.onTimeTick() - clock?.largeClock?.events?.onTimeTick() - } + private fun refreshTime() { + clock?.smallClock?.events?.onTimeTick() + clock?.largeClock?.events?.onTimeTick() + } + } @VisibleForTesting internal fun listenForDnd(scope: CoroutineScope): Job { @@ -477,7 +474,6 @@ constructor( listenForAnyStateToAodTransition(this) listenForAnyStateToLockscreenTransition(this) listenForAnyStateToDozingTransition(this) - listenForScreenPowerOn(this) } } smallTimeListener?.update(shouldTimeListenerRun) @@ -647,17 +643,6 @@ constructor( } } - @VisibleForTesting - internal fun listenForScreenPowerOn(scope: CoroutineScope): Job { - return scope.launch { - powerInteractor.screenPowerState.collect { powerState -> - if (powerState != ScreenPowerState.SCREEN_OFF) { - refreshTime() - } - } - } - } - class TimeListener(val clockFace: ClockFaceController, val executor: DelayableExecutor) { val predrawListener = ViewTreeObserver.OnPreDrawListener { diff --git a/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt index 3f332f769c6e..8f6a54c4ae36 100644 --- a/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt +++ b/packages/SystemUI/src/com/android/keyguard/ConnectedDisplayKeyguardPresentation.kt @@ -91,6 +91,10 @@ constructor( super.onCreate(savedInstanceState) onCreateV2() + val window = window ?: return + val layoutParams = window.attributes + layoutParams.flags = layoutParams.flags or WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER + window.attributes = layoutParams } fun onCreateV2() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt index 953cf88feccb..943cbe87c8c2 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt @@ -49,6 +49,7 @@ data class KeyguardFingerprintListenModel( var systemUser: Boolean = false, var udfps: Boolean = false, var userDoesNotHaveTrust: Boolean = false, + var communalShowing: Boolean = false, ) : KeyguardListenModel() { /** List of [String] to be used as a [Row] with [DumpsysTableLogger]. */ @@ -81,6 +82,7 @@ data class KeyguardFingerprintListenModel( systemUser.toString(), udfps.toString(), userDoesNotHaveTrust.toString(), + communalShowing.toString(), ) } @@ -122,6 +124,7 @@ data class KeyguardFingerprintListenModel( systemUser = model.systemUser udfps = model.udfps userDoesNotHaveTrust = model.userDoesNotHaveTrust + communalShowing = model.communalShowing } } @@ -170,6 +173,7 @@ data class KeyguardFingerprintListenModel( "systemUser", "underDisplayFingerprint", "userDoesNotHaveTrust", + "communalShowing", ) } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 8cfb4c5592aa..ff7b2b025539 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -1242,7 +1242,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard public void reinflateViewFlipper( KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedListener) { mSecurityViewFlipperController.clearViews(); - mSecurityViewFlipperController.asynchronouslyInflateView(mCurrentSecurityMode, + mSecurityViewFlipperController.getSecurityView(mCurrentSecurityMode, mKeyguardSecurityCallback, (controller) -> { mView.updateSecurityViewFlipper(); onViewInflatedListener.onViewInflated(controller); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java index 120045fc058b..641cac51785f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java @@ -23,7 +23,6 @@ import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE; import android.util.Log; import android.view.LayoutInflater; -import androidx.annotation.Nullable; import androidx.asynclayoutinflater.view.AsyncLayoutInflater; import com.android.internal.annotations.VisibleForTesting; @@ -35,7 +34,9 @@ import com.android.systemui.res.R; import com.android.systemui.util.ViewController; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javax.inject.Inject; @@ -56,6 +57,8 @@ public class KeyguardSecurityViewFlipperController private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory; private final Factory mKeyguardSecurityViewControllerFactory; private final FeatureFlags mFeatureFlags; + private final List<OnViewInflatedCallback> mOnViewInflatedListeners = new ArrayList<>(); + private final Set<SecurityMode> mSecurityModeInProgress = new HashSet<>(); @Inject protected KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view, @@ -106,7 +109,13 @@ public class KeyguardSecurityViewFlipperController } } - asynchronouslyInflateView(securityMode, keyguardSecurityCallback, onViewInflatedCallback); + // Prevent multiple inflations for the same security mode. Instead, add callback to a list + // and then notify each in order when the view is inflated. + mOnViewInflatedListeners.add(onViewInflatedCallback); + if (!mSecurityModeInProgress.contains(securityMode)) { + mSecurityModeInProgress.add(securityMode); + asynchronouslyInflateView(securityMode, keyguardSecurityCallback); + } } /** @@ -117,9 +126,8 @@ public class KeyguardSecurityViewFlipperController * @param securityMode * @param keyguardSecurityCallback */ - public void asynchronouslyInflateView(SecurityMode securityMode, - KeyguardSecurityCallback keyguardSecurityCallback, - @Nullable OnViewInflatedCallback onViewInflatedListener) { + private void asynchronouslyInflateView(SecurityMode securityMode, + KeyguardSecurityCallback keyguardSecurityCallback) { int layoutId = mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE) ? getLayoutIdFor(securityMode) : getLegacyLayoutIdFor(securityMode); if (layoutId != 0) { @@ -129,24 +137,26 @@ public class KeyguardSecurityViewFlipperController mAsyncLayoutInflater.inflate(layoutId, mView, (view, resId, parent) -> { mView.addView(view); + mSecurityModeInProgress.remove(securityMode); KeyguardInputViewController<KeyguardInputView> childController = mKeyguardSecurityViewControllerFactory.create( (KeyguardInputView) view, securityMode, keyguardSecurityCallback); childController.init(); mChildren.add(childController); - if (onViewInflatedListener != null) { - onViewInflatedListener.onViewInflated(childController); - // Single bouncer constrains are default - if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)) { - boolean useSplitBouncer = - getResources().getBoolean(R.bool.update_bouncer_constraints) - && getResources().getConfiguration().orientation - == ORIENTATION_LANDSCAPE; + for (OnViewInflatedCallback callback : mOnViewInflatedListeners) { + callback.onViewInflated(childController); + } + mOnViewInflatedListeners.clear(); - updateConstraints(useSplitBouncer); - } + // Single bouncer constrains are default + if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)) { + boolean useSplitBouncer = + getResources().getBoolean(R.bool.update_bouncer_constraints) + && getResources().getConfiguration().orientation + == ORIENTATION_LANDSCAPE; + updateConstraints(useSplitBouncer); } }); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 61038ef1a72d..c266a5b47cff 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -43,6 +43,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; +import static com.android.systemui.Flags.glanceableHubV2; import static com.android.systemui.Flags.simPinBouncerReset; import static com.android.systemui.Flags.simPinUseSlotId; import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED; @@ -128,6 +129,7 @@ import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider; import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; @@ -294,6 +296,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final Provider<JavaAdapter> mJavaAdapter; private final Provider<SceneInteractor> mSceneInteractor; private final Provider<AlternateBouncerInteractor> mAlternateBouncerInteractor; + private final CommunalSceneInteractor mCommunalSceneInteractor; private final AuthController mAuthController; private final UiEventLogger mUiEventLogger; private final Set<String> mAllowFingerprintOnOccludingActivitiesFromPackage; @@ -404,6 +407,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab protected int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED; private boolean mFingerprintDetectRunning; private boolean mIsDreaming; + private boolean mCommunalShowing; private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private final FingerprintInteractiveToAuthProvider mFingerprintInteractiveToAuthProvider; @@ -2205,7 +2209,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab IActivityTaskManager activityTaskManagerService, Provider<AlternateBouncerInteractor> alternateBouncerInteractor, Provider<JavaAdapter> javaAdapter, - Provider<SceneInteractor> sceneInteractor) { + Provider<SceneInteractor> sceneInteractor, + CommunalSceneInteractor communalSceneInteractor) { mContext = context; mSubscriptionManager = subscriptionManager; mUserTracker = userTracker; @@ -2254,6 +2259,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mAlternateBouncerInteractor = alternateBouncerInteractor; mJavaAdapter = javaAdapter; mSceneInteractor = sceneInteractor; + mCommunalSceneInteractor = communalSceneInteractor; mHandler = new Handler(mainLooper) { @Override @@ -2535,6 +2541,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab ); } + if (glanceableHubV2()) { + mJavaAdapter.get().alwaysCollectFlow( + mCommunalSceneInteractor.isCommunalVisible(), + this::onCommunalShowingChanged + ); + } + // start() can be invoked in the middle of user switching, so check for this state and issue // the call manually as that important event was missed. if (mUserTracker.isUserSwitching()) { @@ -2837,6 +2850,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } /** + * Sets whether the communal hub is showing. + */ + @VisibleForTesting + void onCommunalShowingChanged(boolean showing) { + mCommunalShowing = showing; + updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); + } + + /** * Whether the alternate bouncer is showing. */ public void setAlternateBouncerShowing(boolean showing) { @@ -2998,11 +3020,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean strongerAuthRequired = !isUnlockingWithFingerprintAllowed(); final boolean shouldListenBouncerState = !strongerAuthRequired || !isPrimaryBouncerShowingOrWillBeShowing(); + final boolean isUdfpsAuthRequiredOnCommunal = + !mCommunalShowing || isAlternateBouncerShowing(); final boolean shouldListenUdfpsState = !isUdfps || (!userCanSkipBouncer && !strongerAuthRequired - && userDoesNotHaveTrust); + && userDoesNotHaveTrust + && (!glanceableHubV2() || isUdfpsAuthRequiredOnCommunal)); boolean shouldListen = shouldListenKeyguardState && shouldListenUserState @@ -3033,7 +3058,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mSwitchingUser, mIsSystemUser, isUdfps, - userDoesNotHaveTrust)); + userDoesNotHaveTrust, + mCommunalShowing)); return shouldListen; } @@ -3332,6 +3358,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } + /** Triggers an out of band time update */ + public void triggerTimeUpdate() { + mHandler.sendEmptyMessage(MSG_TIME_UPDATE); + } + /** * Handle {@link #MSG_TIME_UPDATE} */ diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java index e7470a34a065..102efcf7badd 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java @@ -17,6 +17,7 @@ package com.android.systemui.accessibility.floatingmenu; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; import android.content.Context; @@ -90,9 +91,11 @@ class MenuViewLayerController implements IAccessibilityFloatingMenu { WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); + params.setTitle("FloatingMenu"); params.receiveInsetsIgnoringZOrder = true; params.privateFlags |= - PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION | SYSTEM_FLAG_SHOW_FOR_ALL_USERS; + PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION | SYSTEM_FLAG_SHOW_FOR_ALL_USERS + | PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION; params.windowAnimations = android.R.style.Animation_Translucent; // Insets are configured to allow the menu to display over navigation and system bars. params.setFitInsetsTypes(0); diff --git a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java index 081d2a087b07..b7b31566a5e9 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java @@ -75,8 +75,8 @@ public class AmbientStatusBarView extends ConstraintLayout { private ShadowInfo mAmbientShadowInfo; private int mDrawableSize; private int mDrawableInsetSize; - private static final float KEY_SHADOW_ALPHA = 0.8f; - private static final float AMBIENT_SHADOW_ALPHA = 0.6f; + private static final float KEY_SHADOW_ALPHA = 0.9f; + private static final float AMBIENT_SHADOW_ALPHA = 0.7f; public AmbientStatusBarView(Context context) { this(context, null); @@ -102,14 +102,14 @@ public class AmbientStatusBarView extends ConstraintLayout { super.onFinishInflate(); mKeyShadowInfo = createShadowInfo( - R.dimen.dream_overlay_status_bar_key_text_shadow_radius, + R.dimen.dream_overlay_icon_shadow_radius, R.dimen.dream_overlay_status_bar_key_text_shadow_dx, R.dimen.dream_overlay_status_bar_key_text_shadow_dy, KEY_SHADOW_ALPHA ); mAmbientShadowInfo = createShadowInfo( - R.dimen.dream_overlay_status_bar_ambient_text_shadow_radius, + R.dimen.dream_overlay_icon_ambient_shadow_radius, R.dimen.dream_overlay_status_bar_ambient_text_shadow_dx, R.dimen.dream_overlay_status_bar_ambient_text_shadow_dy, AMBIENT_SHADOW_ALPHA diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/colors/ShadeColors.kt b/packages/SystemUI/src/com/android/systemui/common/shared/colors/ShadeColors.kt new file mode 100644 index 000000000000..70ace6a6d038 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/common/shared/colors/ShadeColors.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2025 The Android Open 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.shared.colors + +import android.content.res.Resources +import android.graphics.Color +import com.android.internal.graphics.ColorUtils +import com.android.systemui.res.R + +object ShadeColors { + @JvmStatic + fun Resources.shadeBasePanel(): Int { + val layerAbove = + ColorUtils.setAlphaComponent(getColor(R.color.shade_panel), (0.4f * 255).toInt()) + val layerBelow = ColorUtils.setAlphaComponent(Color.WHITE, (0.1f * 255).toInt()) + return ColorUtils.compositeColors(layerAbove, layerBelow) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt b/packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt new file mode 100644 index 000000000000..d4027c029a0a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2025 The Android Open 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.shared.colors + +import android.content.res.Resources +import android.graphics.Color +import com.android.internal.graphics.ColorUtils +import com.android.systemui.res.R + +object SurfaceEffectColors { + @JvmStatic + fun Resources.surfaceEffect0(): Int { + return getColor(com.android.internal.R.color.surface_effect_0) + } + + @JvmStatic + fun Resources.surfaceEffect1(): Int { + return getColor(com.android.internal.R.color.surface_effect_1) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt index 7fcdd9596049..5671fa49c716 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt @@ -19,15 +19,16 @@ package com.android.systemui.common.ui.data.repository import android.content.Context import android.content.res.Configuration +import android.view.Display import android.view.DisplayInfo import androidx.annotation.DimenRes import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.wrapper.DisplayUtilsWrapper +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import dagger.Binds import dagger.Module import dagger.Provides @@ -57,7 +58,7 @@ interface ConfigurationRepository { val configurationValues: Flow<Configuration> /** Emits the latest display this configuration controller has been moved to. */ - val onMovedToDisplay: Flow<Int> + val onMovedToDisplay: StateFlow<Int> fun getResolutionScale(): Float @@ -121,20 +122,21 @@ constructor( configurationController.addCallback(callback) awaitClose { configurationController.removeCallback(callback) } } - override val onMovedToDisplay: Flow<Int> - get() = conflatedCallbackFlow { - val callback = - object : ConfigurationController.ConfigurationListener { - override fun onMovedToDisplay( - newDisplayId: Int, - newConfiguration: Configuration?, - ) { - trySend(newDisplayId) + override val onMovedToDisplay: StateFlow<Int> = + conflatedCallbackFlow { + val callback = + object : ConfigurationController.ConfigurationListener { + override fun onMovedToDisplay( + newDisplayId: Int, + newConfiguration: Configuration?, + ) { + trySend(newDisplayId) + } } - } - configurationController.addCallback(callback) - awaitClose { configurationController.removeCallback(callback) } - } + configurationController.addCallback(callback) + awaitClose { configurationController.removeCallback(callback) } + } + .stateIn(scope, SharingStarted.Eagerly, Display.DEFAULT_DISPLAY) override val scaleForResolution: StateFlow<Float> = onConfigurationChange diff --git a/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingCommandListener.kt b/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingCommandListener.kt deleted file mode 100644 index c7b7050340a0..000000000000 --- a/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingCommandListener.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2025 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.communal - -import android.annotation.SuppressLint -import android.app.DreamManager -import com.android.systemui.CoreStartable -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.commandline.Command -import com.android.systemui.statusbar.commandline.CommandRegistry -import java.io.PrintWriter -import javax.inject.Inject - -@SysUISingleton -class DevicePosturingCommandListener -@Inject -constructor(private val commandRegistry: CommandRegistry, private val dreamManager: DreamManager) : - CoreStartable { - private val command = DevicePosturingCommand() - - override fun start() { - commandRegistry.registerCommand(COMMAND_ROOT) { command } - } - - internal inner class DevicePosturingCommand : Command { - @SuppressLint("MissingPermission") - override fun execute(pw: PrintWriter, args: List<String>) { - val arg = args.getOrNull(0) - if (arg == null || arg.lowercase() == "help") { - help(pw) - return - } - - when (arg.lowercase()) { - "true" -> dreamManager.setDevicePostured(true) - "false" -> dreamManager.setDevicePostured(false) - else -> { - pw.println("Invalid argument!") - help(pw) - } - } - } - - override fun help(pw: PrintWriter) { - pw.println("Usage: $ adb shell cmd statusbar device-postured <true|false>") - } - } - - private companion object { - const val COMMAND_ROOT = "device-postured" - } -} diff --git a/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingListener.kt b/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingListener.kt new file mode 100644 index 000000000000..47040fa4a572 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingListener.kt @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal + +import android.annotation.SuppressLint +import android.app.DreamManager +import android.service.dreams.Flags.allowDreamWhenPostured +import com.android.app.tracing.coroutines.launchInTraced +import com.android.systemui.CoreStartable +import com.android.systemui.communal.posturing.domain.interactor.PosturingInteractor +import com.android.systemui.communal.posturing.shared.model.PosturedState +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.log.dagger.CommunalTableLog +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable +import com.android.systemui.statusbar.commandline.Command +import com.android.systemui.statusbar.commandline.CommandRegistry +import java.io.PrintWriter +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.onEach + +@SysUISingleton +class DevicePosturingListener +@Inject +constructor( + private val commandRegistry: CommandRegistry, + private val dreamManager: DreamManager, + private val interactor: PosturingInteractor, + @Background private val bgScope: CoroutineScope, + @CommunalTableLog private val tableLogBuffer: TableLogBuffer, +) : CoreStartable { + private val command = DevicePosturingCommand() + + @SuppressLint("MissingPermission") + override fun start() { + if (!allowDreamWhenPostured()) { + return + } + + interactor.postured + .distinctUntilChanged() + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnPrefix = "", + columnName = "postured", + initialValue = false, + ) + .onEach { postured -> dreamManager.setDevicePostured(postured) } + .launchInTraced("$TAG#collectPostured", bgScope) + + commandRegistry.registerCommand(COMMAND_ROOT) { command } + } + + internal inner class DevicePosturingCommand : Command { + @SuppressLint("MissingPermission") + override fun execute(pw: PrintWriter, args: List<String>) { + val arg = args.getOrNull(0) + if (arg == null || arg.lowercase() == "help") { + help(pw) + return + } + + val state = + when (arg.lowercase()) { + "true" -> PosturedState.Postured(confidence = 1f) + "false" -> PosturedState.NotPostured + "clear" -> PosturedState.Unknown + else -> { + pw.println("Invalid argument!") + help(pw) + null + } + } + state?.let { interactor.setValueForDebug(it) } + } + + override fun help(pw: PrintWriter) { + pw.println("Usage: $ adb shell cmd statusbar device-postured <true|false|clear>") + } + } + + private companion object { + const val COMMAND_ROOT = "device-postured" + const val TAG = "DevicePosturingListener" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt index e3443227685f..7358aa7b3fcd 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalStartableModule.kt @@ -22,7 +22,7 @@ import com.android.systemui.communal.CommunalDreamStartable import com.android.systemui.communal.CommunalMetricsStartable import com.android.systemui.communal.CommunalOngoingContentStartable import com.android.systemui.communal.CommunalSceneStartable -import com.android.systemui.communal.DevicePosturingCommandListener +import com.android.systemui.communal.DevicePosturingListener import com.android.systemui.communal.log.CommunalLoggerStartable import com.android.systemui.communal.widgets.CommunalAppWidgetHostStartable import com.android.systemui.dagger.qualifiers.PerUser @@ -71,6 +71,6 @@ interface CommunalStartableModule { @Binds @IntoMap - @ClassKey(DevicePosturingCommandListener::class) - fun bindDevicePosturingCommandListener(impl: DevicePosturingCommandListener): CoreStartable + @ClassKey(DevicePosturingListener::class) + fun bindDevicePosturingistener(impl: DevicePosturingListener): CoreStartable } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt index 4de39c457f3b..a02bc8b89910 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt @@ -51,6 +51,12 @@ interface CommunalPrefsRepository { /** Save the CTA tile dismissed state for the current user. */ suspend fun setCtaDismissed(user: UserInfo) + + /** Whether hub onboarding has been dismissed. */ + fun isHubOnboardingDismissed(user: UserInfo): Flow<Boolean> + + /** Save the hub onboarding dismissed state for the current user. */ + suspend fun setHubOnboardingDismissed(user: UserInfo) } @OptIn(ExperimentalCoroutinesApi::class) @@ -65,9 +71,6 @@ constructor( ) : CommunalPrefsRepository { private val logger by lazy { Logger(logBuffer, TAG) } - override fun isCtaDismissed(user: UserInfo): Flow<Boolean> = - readKeyForUser(user, CTA_DISMISSED_STATE) - /** * Emits an event each time a Backup & Restore restoration job is completed, and once at the * start of collection. @@ -82,18 +85,29 @@ constructor( .onEach { logger.i("Restored state for communal preferences.") } .emitOnStart() + override fun isCtaDismissed(user: UserInfo): Flow<Boolean> = + readKeyForUser(user, CTA_DISMISSED_STATE) + override suspend fun setCtaDismissed(user: UserInfo) = withContext(bgDispatcher) { getSharedPrefsForUser(user).edit().putBoolean(CTA_DISMISSED_STATE, true).apply() logger.i("Dismissed CTA tile") } + override fun isHubOnboardingDismissed(user: UserInfo): Flow<Boolean> = + readKeyForUser(user, HUB_ONBOARDING_DISMISSED_STATE) + + override suspend fun setHubOnboardingDismissed(user: UserInfo) = + withContext(bgDispatcher) { + getSharedPrefsForUser(user) + .edit() + .putBoolean(HUB_ONBOARDING_DISMISSED_STATE, true) + .apply() + logger.i("Dismissed hub onboarding") + } + private fun getSharedPrefsForUser(user: UserInfo): SharedPreferences { - return userFileManager.getSharedPreferences( - FILE_NAME, - Context.MODE_PRIVATE, - user.id, - ) + return userFileManager.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE, user.id) } private fun readKeyForUser(user: UserInfo, key: String): Flow<Boolean> { @@ -109,5 +123,6 @@ constructor( const val TAG = "CommunalPrefsRepository" const val FILE_NAME = "communal_hub_prefs" const val CTA_DISMISSED_STATE = "cta_dismissed" + const val HUB_ONBOARDING_DISMISSED_STATE = "hub_onboarding_dismissed" } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractor.kt index 0b5f40d8041e..76e6cde4ad81 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractor.kt @@ -32,6 +32,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch @OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton @@ -63,6 +64,24 @@ constructor( suspend fun setCtaDismissed(user: UserInfo = userTracker.userInfo) = repository.setCtaDismissed(user) + val isHubOnboardingDismissed: Flow<Boolean> = + userInteractor.selectedUserInfo + .flatMapLatest { user -> repository.isHubOnboardingDismissed(user) } + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnPrefix = "", + columnName = "isHubOnboardingDismissed", + initialValue = false, + ) + .stateIn( + scope = bgScope, + started = SharingStarted.WhileSubscribed(), + initialValue = false, + ) + + fun setHubOnboardingDismissed(user: UserInfo = userTracker.userInfo) = + bgScope.launch { repository.setHubOnboardingDismissed(user) } + private companion object { const val TAG = "CommunalPrefsInteractor" } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/HubOnboardingInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/HubOnboardingInteractor.kt new file mode 100644 index 000000000000..26a0a7930b4a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/HubOnboardingInteractor.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.domain.interactor + +import com.android.systemui.communal.data.repository.CommunalSettingsRepository +import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf +import com.android.systemui.util.kotlin.BooleanFlowOperators.not +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf + +class HubOnboardingInteractor +@Inject +constructor( + communalSceneInteractor: CommunalSceneInteractor, + communalSettingsRepository: CommunalSettingsRepository, + private val communalPrefsInteractor: CommunalPrefsInteractor, +) { + /** Dismiss hub onboarding education. */ + fun setHubOnboardingDismissed() = communalPrefsInteractor.setHubOnboardingDismissed() + + /** Should hub onboarding be shown to the user. */ + val shouldShowHubOnboarding: Flow<Boolean> = + if (communalSettingsRepository.getV2FlagEnabled()) { + allOf( + not(communalPrefsInteractor.isHubOnboardingDismissed), + communalSceneInteractor.isIdleOnCommunal, + ) + } else { + flowOf(false) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/posturing/dagger/NoopPosturingModule.kt b/packages/SystemUI/src/com/android/systemui/communal/posturing/dagger/NoopPosturingModule.kt new file mode 100644 index 000000000000..f576a2000e05 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/posturing/dagger/NoopPosturingModule.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.posturing.dagger + +import com.android.systemui.communal.posturing.data.repository.NoOpPosturingRepository +import com.android.systemui.communal.posturing.data.repository.PosturingRepository +import dagger.Binds +import dagger.Module + +/** Module providing a reference implementation of the posturing signal. */ +@Module +interface NoopPosturingModule { + /** Binds a reference implementation of the posturing repository */ + @Binds fun bindPosturingRepository(impl: NoOpPosturingRepository): PosturingRepository +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/NoOpPosturingRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/NoOpPosturingRepository.kt new file mode 100644 index 000000000000..c5f357f556ca --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/NoOpPosturingRepository.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.posturing.data.repository + +import com.android.systemui.communal.posturing.shared.model.PosturedState +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +@SysUISingleton +class NoOpPosturingRepository @Inject constructor() : PosturingRepository { + override val posturedState: Flow<PosturedState> = + MutableStateFlow(PosturedState.Unknown).asStateFlow() +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/PosturingRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/PosturingRepository.kt new file mode 100644 index 000000000000..dae1a47f5be0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/posturing/data/repository/PosturingRepository.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.posturing.data.repository + +import com.android.systemui.communal.posturing.shared.model.PosturedState +import kotlinx.coroutines.flow.Flow + +/** + * Repository which retrieves the postured state of the device. Posturing is defined as the device + * being stationary and upright. + */ +interface PosturingRepository { + /** Whether the device is currently stationary and upright. */ + val posturedState: Flow<PosturedState> +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractor.kt new file mode 100644 index 000000000000..cd81dea9cad1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractor.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.posturing.domain.interactor + +import com.android.systemui.communal.posturing.data.repository.PosturingRepository +import com.android.systemui.communal.posturing.shared.model.PosturedState +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine + +@SysUISingleton +class PosturingInteractor @Inject constructor(repository: PosturingRepository) { + private val debugPostured = MutableStateFlow<PosturedState>(PosturedState.Unknown) + + val postured: Flow<Boolean> = + combine(repository.posturedState, debugPostured) { postured, debugValue -> + debugValue.asBoolean() ?: postured.asBoolean() ?: false + } + + fun setValueForDebug(value: PosturedState) { + debugPostured.value = value + } +} + +fun PosturedState.asBoolean(): Boolean? { + return when (this) { + is PosturedState.Postured -> true + PosturedState.NotPostured -> false + PosturedState.Unknown -> null + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/posturing/shared/model/PosturedState.kt b/packages/SystemUI/src/com/android/systemui/communal/posturing/shared/model/PosturedState.kt new file mode 100644 index 000000000000..431ca67315eb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/posturing/shared/model/PosturedState.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.posturing.shared.model + +sealed interface PosturedState { + /** Represents postured state */ + data class Postured(val confidence: Float) : PosturedState + + /** Represents unknown/uninitialized state */ + data object Unknown : PosturedState + + /** Represents state where we are not postured */ + data object NotPostured : PosturedState +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/HubOnboardingViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/HubOnboardingViewModel.kt new file mode 100644 index 000000000000..5245800ba3d1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/HubOnboardingViewModel.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.ui.viewmodel + +import android.annotation.SuppressLint +import com.android.systemui.communal.domain.interactor.HubOnboardingInteractor +import com.android.systemui.lifecycle.ExclusiveActivatable +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.coroutineScope + +class HubOnboardingViewModel +@AssistedInject +constructor(private val hubOnboardingInteractor: HubOnboardingInteractor) : ExclusiveActivatable() { + + val shouldShowHubOnboarding = hubOnboardingInteractor.shouldShowHubOnboarding + + fun onDismissed() { + hubOnboardingInteractor.setHubOnboardingDismissed() + } + + @SuppressLint("MissingPermission") + override suspend fun onActivated(): Nothing = coroutineScope { awaitCancellation() } + + @AssistedFactory + interface Factory { + fun create(): HubOnboardingViewModel + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt index be428a84da2f..9e9e9998a82e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt @@ -25,14 +25,14 @@ import com.android.systemui.controls.controller.ControlInfo * This model is used to show controls separated by zones. * * The model will sort the controls and zones in the following manner: - * * The zones will be sorted in a first seen basis - * * The controls in each zone will be sorted in a first seen basis. + * * The zones will be sorted in a first seen basis + * * The controls in each zone will be sorted in a first seen basis. * - * The controls passed should belong to the same structure, as an instance of this model will be - * created for each structure. + * The controls passed should belong to the same structure, as an instance of this model will be + * created for each structure. * - * The list of favorite ids can contain ids for controls not passed to this model. Those will be - * filtered out. + * The list of favorite ids can contain ids for controls not passed to this model. Those will be + * filtered out. * * @property controls List of controls as returned by loading * @property initialFavoriteIds sorted ids of favorite controls. @@ -43,7 +43,7 @@ class AllModel( private val controls: List<ControlStatus>, initialFavoriteIds: List<String>, private val emptyZoneString: CharSequence, - private val controlsModelCallback: ControlsModel.ControlsModelCallback + private val controlsModelCallback: ControlsModel.ControlsModelCallback, ) : ControlsModel { private var modified = false @@ -51,12 +51,11 @@ class AllModel( override val moveHelper = null override val favorites: List<ControlInfo> - get() = favoriteIds.mapNotNull { id -> - val control = controls.firstOrNull { it.control.controlId == id }?.control - control?.let { - ControlInfo.fromControl(it) + get() = + favoriteIds.mapNotNull { id -> + val control = controls.firstOrNull { it.control.controlId == id }?.control + control?.let { ControlInfo.fromControl(it) } } - } private val favoriteIds = run { val ids = controls.mapTo(HashSet()) { it.control.controlId } @@ -66,15 +65,17 @@ class AllModel( override val elements: List<ElementWrapper> = createWrappers(controls) override fun changeFavoriteStatus(controlId: String, favorite: Boolean) { - val toChange = elements.firstOrNull { - it is ControlStatusWrapper && it.controlStatus.control.controlId == controlId - } as ControlStatusWrapper? + val toChange = + elements.firstOrNull { + it is ControlStatusWrapper && it.controlStatus.control.controlId == controlId + } as ControlStatusWrapper? if (favorite == toChange?.controlStatus?.favorite) return - val changed: Boolean = if (favorite) { - favoriteIds.add(controlId) - } else { - favoriteIds.remove(controlId) - } + val changed: Boolean = + if (favorite) { + favoriteIds.add(controlId) + } else { + favoriteIds.remove(controlId) + } if (changed) { if (!modified) { modified = true @@ -82,15 +83,14 @@ class AllModel( } controlsModelCallback.onChange() } - toChange?.let { - it.controlStatus.favorite = favorite - } + toChange?.let { it.controlStatus.favorite = favorite } } private fun createWrappers(list: List<ControlStatus>): List<ElementWrapper> { - val map = list.groupByTo(OrderedMap(ArrayMap<CharSequence, MutableList<ControlStatus>>())) { - it.control.zone ?: "" - } + val map = + list.groupByTo(OrderedMap(ArrayMap<CharSequence, MutableList<ControlStatus>>())) { + it.control.zone ?: "" + } val output = mutableListOf<ElementWrapper>() var emptyZoneValues: Sequence<ControlStatusWrapper>? = null for (zoneName in map.orderedKeys) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt index f034851e5d80..3ea415675bdf 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt @@ -36,10 +36,11 @@ import androidx.core.view.AccessibilityDelegateCompat import androidx.core.view.ViewCompat import androidx.core.view.accessibility.AccessibilityNodeInfoCompat import androidx.recyclerview.widget.RecyclerView -import com.android.systemui.res.R import com.android.systemui.controls.ControlInterface import com.android.systemui.controls.ui.CanUseIconPredicate import com.android.systemui.controls.ui.RenderInfo +import com.android.systemui.res.R +import com.android.systemui.utils.SafeIconLoader private typealias ModelFavoriteChanger = (String, Boolean) -> Unit @@ -54,6 +55,7 @@ private typealias ModelFavoriteChanger = (String, Boolean) -> Unit class ControlAdapter( private val elevation: Float, private val currentUserId: Int, + private val safeIconLoader: SafeIconLoader, ) : RecyclerView.Adapter<Holder>() { companion object { @@ -62,15 +64,14 @@ class ControlAdapter( const val TYPE_DIVIDER = 2 /** - * For low-dp width screens that also employ an increased font scale, adjust the - * number of columns. This helps prevent text truncation on these devices. - * + * For low-dp width screens that also employ an increased font scale, adjust the number of + * columns. This helps prevent text truncation on these devices. */ @JvmStatic fun findMaxColumns(res: Resources): Int { var maxColumns = res.getInteger(R.integer.controls_max_columns) val maxColumnsAdjustWidth = - res.getInteger(R.integer.controls_max_columns_adjust_below_width_dp) + res.getInteger(R.integer.controls_max_columns_adjust_below_width_dp) val outValue = TypedValue() res.getValue(R.dimen.controls_max_columns_adjust_above_font_scale, outValue, true) @@ -78,10 +79,12 @@ class ControlAdapter( val config = res.configuration val isPortrait = config.orientation == Configuration.ORIENTATION_PORTRAIT - if (isPortrait && + if ( + isPortrait && config.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED && config.screenWidthDp <= maxColumnsAdjustWidth && - config.fontScale >= maxColumnsAdjustFontScale) { + config.fontScale >= maxColumnsAdjustFontScale + ) { maxColumns-- } @@ -106,11 +109,12 @@ class ControlAdapter( rightMargin = 0 } elevation = this@ControlAdapter.elevation - background = parent.context.getDrawable( - R.drawable.control_background_ripple) + background = + parent.context.getDrawable(R.drawable.control_background_ripple) }, currentUserId, model?.moveHelper, // Indicates that position information is needed + safeIconLoader, ) { id, favorite -> model?.changeFavoriteStatus(id, favorite) } @@ -119,8 +123,13 @@ class ControlAdapter( ZoneHolder(layoutInflater.inflate(R.layout.controls_zone_header, parent, false)) } TYPE_DIVIDER -> { - DividerHolder(layoutInflater.inflate( - R.layout.controls_horizontal_divider_with_empty, parent, false)) + DividerHolder( + layoutInflater.inflate( + R.layout.controls_horizontal_divider_with_empty, + parent, + false, + ) + ) } else -> throw IllegalStateException("Wrong viewType: $viewType") } @@ -134,9 +143,7 @@ class ControlAdapter( override fun getItemCount() = model?.elements?.size ?: 0 override fun onBindViewHolder(holder: Holder, index: Int) { - model?.let { - holder.bindData(it.elements[index]) - } + model?.let { holder.bindData(it.elements[index]) } } override fun onBindViewHolder(holder: Holder, position: Int, payloads: MutableList<Any>) { @@ -166,13 +173,12 @@ class ControlAdapter( /** * Holder for binding views in the [RecyclerView]- + * * @param view the [View] for this [Holder] */ sealed class Holder(view: View) : RecyclerView.ViewHolder(view) { - /** - * Bind the data from the model into the view - */ + /** Bind the data from the model into the view */ abstract fun bindData(wrapper: ElementWrapper) open fun updateFavorite(favorite: Boolean) {} @@ -181,12 +187,13 @@ sealed class Holder(view: View) : RecyclerView.ViewHolder(view) { /** * Holder for using with [DividerWrapper] to display a divider between zones. * - * The divider can be shown or hidden. It also has a view the height of a control, that can - * be toggled visible or gone. + * The divider can be shown or hidden. It also has a view the height of a control, that can be + * toggled visible or gone. */ private class DividerHolder(view: View) : Holder(view) { private val frame: View = itemView.requireViewById(R.id.frame) private val divider: View = itemView.requireViewById(R.id.divider) + override fun bindData(wrapper: ElementWrapper) { wrapper as DividerWrapper frame.visibility = if (wrapper.showNone) View.VISIBLE else View.GONE @@ -194,9 +201,7 @@ private class DividerHolder(view: View) : Holder(view) { } } -/** - * Holder for using with [ZoneNameWrapper] to display names of zones. - */ +/** Holder for using with [ZoneNameWrapper] to display names of zones. */ private class ZoneHolder(view: View) : Holder(view) { private val zone: TextView = itemView as TextView @@ -208,15 +213,17 @@ private class ZoneHolder(view: View) : Holder(view) { /** * Holder for using with [ControlStatusWrapper] to display names of zones. + * * @param moveHelper a helper interface to facilitate a11y rearranging. Null indicates no - * rearranging - * @param favoriteCallback this callback will be called whenever the favorite state of the - * [Control] this view represents changes. + * rearranging + * @param favoriteCallback this callback will be called whenever the favorite state of the [Control] + * this view represents changes. */ internal class ControlHolder( view: View, currentUserId: Int, val moveHelper: ControlsModel.MoveHelper?, + val safeIconLoader: SafeIconLoader, val favoriteCallback: ModelFavoriteChanger, ) : Holder(view) { private val favoriteStateDescription = @@ -228,16 +235,16 @@ internal class ControlHolder( private val title: TextView = itemView.requireViewById(R.id.title) private val subtitle: TextView = itemView.requireViewById(R.id.subtitle) private val removed: TextView = itemView.requireViewById(R.id.status) - private val favorite: CheckBox = itemView.requireViewById<CheckBox>(R.id.favorite).apply { - visibility = View.VISIBLE - } + private val favorite: CheckBox = + itemView.requireViewById<CheckBox>(R.id.favorite).apply { visibility = View.VISIBLE } private val canUseIconPredicate = CanUseIconPredicate(currentUserId) - private val accessibilityDelegate = ControlHolderAccessibilityDelegate( - this::stateDescription, - this::getLayoutPosition, - moveHelper - ) + private val accessibilityDelegate = + ControlHolderAccessibilityDelegate( + this::stateDescription, + this::getLayoutPosition, + moveHelper, + ) init { ViewCompat.setAccessibilityDelegate(itemView, accessibilityDelegate) @@ -252,7 +259,9 @@ internal class ControlHolder( } else { val position = layoutPosition + 1 return itemView.context.getString( - R.string.accessibility_control_favorite_position, position) + R.string.accessibility_control_favorite_position, + position, + ) } } @@ -262,11 +271,12 @@ internal class ControlHolder( title.text = wrapper.title subtitle.text = wrapper.subtitle updateFavorite(wrapper.favorite) - removed.text = if (wrapper.removed) { - itemView.context.getText(R.string.controls_removed) - } else { - "" - } + removed.text = + if (wrapper.removed) { + itemView.context.getText(R.string.controls_removed) + } else { + "" + } itemView.setOnClickListener { updateFavorite(!favorite.isChecked) favoriteCallback(wrapper.controlId, favorite.isChecked) @@ -282,7 +292,7 @@ internal class ControlHolder( private fun getRenderInfo( component: ComponentName, - @DeviceTypes.DeviceType deviceType: Int + @DeviceTypes.DeviceType deviceType: Int, ): RenderInfo { return RenderInfo.lookup(itemView.context, component, deviceType) } @@ -292,18 +302,19 @@ internal class ControlHolder( val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme()) icon.imageTintList = null - ci.customIcon - ?.takeIf(canUseIconPredicate) - ?.let { - icon.setImageIcon(it) - } ?: run { - icon.setImageDrawable(ri.icon) - - // Do not color app icons - if (ci.deviceType != DeviceTypes.TYPE_ROUTINE) { - icon.setImageTintList(fg) - } + ci.customIcon?.takeIf(canUseIconPredicate)?.let { + val drawable = safeIconLoader.load(it) + icon.setImageDrawable(drawable) + drawable } + ?: run { + icon.setImageDrawable(ri.icon) + + // Do not color app icons + if (ci.deviceType != DeviceTypes.TYPE_ROUTINE) { + icon.setImageTintList(fg) + } + } } } @@ -317,14 +328,13 @@ internal class ControlHolder( * * @param stateRetriever function to determine the state description based on the favorite state * @param positionRetriever function to obtain the position of this control. It only has to be - * correct in controls that are currently favorites (and therefore can - * be moved). + * correct in controls that are currently favorites (and therefore can be moved). * @param moveHelper helper interface to determine if a control can be moved and actually move it. */ private class ControlHolderAccessibilityDelegate( val stateRetriever: (Boolean) -> CharSequence?, val positionRetriever: () -> Int, - val moveHelper: ControlsModel.MoveHelper? + val moveHelper: ControlsModel.MoveHelper?, ) : AccessibilityDelegateCompat() { var isFavorite = false @@ -369,25 +379,29 @@ private class ControlHolderAccessibilityDelegate( private fun addClickAction(host: View, info: AccessibilityNodeInfoCompat) { // Change the text for the double-tap action - val clickActionString = if (isFavorite) { - host.context.getString(R.string.accessibility_control_change_unfavorite) - } else { - host.context.getString(R.string.accessibility_control_change_favorite) - } - val click = AccessibilityNodeInfoCompat.AccessibilityActionCompat( - AccessibilityNodeInfo.ACTION_CLICK, - // “favorite/unfavorite” - clickActionString) + val clickActionString = + if (isFavorite) { + host.context.getString(R.string.accessibility_control_change_unfavorite) + } else { + host.context.getString(R.string.accessibility_control_change_favorite) + } + val click = + AccessibilityNodeInfoCompat.AccessibilityActionCompat( + AccessibilityNodeInfo.ACTION_CLICK, + // “favorite/unfavorite” + clickActionString, + ) info.addAction(click) } private fun maybeAddMoveBeforeAction(host: View, info: AccessibilityNodeInfoCompat) { if (moveHelper?.canMoveBefore(positionRetriever()) ?: false) { val newPosition = positionRetriever() + 1 - 1 - val moveBefore = AccessibilityNodeInfoCompat.AccessibilityActionCompat( - MOVE_BEFORE_ID, - host.context.getString(R.string.accessibility_control_move, newPosition) - ) + val moveBefore = + AccessibilityNodeInfoCompat.AccessibilityActionCompat( + MOVE_BEFORE_ID, + host.context.getString(R.string.accessibility_control_move, newPosition), + ) info.addAction(moveBefore) info.isContextClickable = true } @@ -396,26 +410,25 @@ private class ControlHolderAccessibilityDelegate( private fun maybeAddMoveAfterAction(host: View, info: AccessibilityNodeInfoCompat) { if (moveHelper?.canMoveAfter(positionRetriever()) ?: false) { val newPosition = positionRetriever() + 1 + 1 - val moveAfter = AccessibilityNodeInfoCompat.AccessibilityActionCompat( - MOVE_AFTER_ID, - host.context.getString(R.string.accessibility_control_move, newPosition) - ) + val moveAfter = + AccessibilityNodeInfoCompat.AccessibilityActionCompat( + MOVE_AFTER_ID, + host.context.getString(R.string.accessibility_control_move, newPosition), + ) info.addAction(moveAfter) info.isContextClickable = true } } } -class MarginItemDecorator( - private val topMargin: Int, - private val sideMargins: Int -) : RecyclerView.ItemDecoration() { +class MarginItemDecorator(private val topMargin: Int, private val sideMargins: Int) : + RecyclerView.ItemDecoration() { override fun getItemOffsets( outRect: Rect, view: View, parent: RecyclerView, - state: RecyclerView.State + state: RecyclerView.State, ) { val position = parent.getChildAdapterPosition(view) if (position == RecyclerView.NO_POSITION) return diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt index 740e011b3d20..e4913cb59768 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt @@ -22,6 +22,7 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.os.Bundle +import android.os.Process import android.util.Log import android.view.View import android.view.ViewGroup @@ -42,6 +43,7 @@ import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.res.R import com.android.systemui.settings.UserTracker +import com.android.systemui.utils.SafeIconLoader import java.util.concurrent.Executor import javax.inject.Inject @@ -53,6 +55,8 @@ constructor( private val controller: ControlsControllerImpl, private val userTracker: UserTracker, private val customIconCache: CustomIconCache, + private val controlsListingController: ControlsListingController, + private val safeIconLoaderFactory: SafeIconLoader.Factory, ) : ComponentActivity(), ControlsManagementActivity { companion object { @@ -258,8 +262,18 @@ constructor( val elevation = resources.getFloat(R.dimen.control_card_elevation) val recyclerView = requireViewById<RecyclerView>(R.id.list) recyclerView.alpha = 0.0f + val uid = + controlsListingController + .getCurrentServices() + .firstOrNull { it.componentName == component } + ?.serviceInfo + ?.applicationInfo + ?.uid ?: Process.INVALID_UID + val packageName = component.packageName + val safeIconLoader = safeIconLoaderFactory.create(uid, packageName, userTracker.userId) + val adapter = - ControlAdapter(elevation, userTracker.userId).apply { + ControlAdapter(elevation, userTracker.userId, safeIconLoader).apply { registerAdapterDataObserver( object : RecyclerView.AdapterDataObserver() { var hasAnimated = false diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt index ab55c5326b55..80c9d0bb8858 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt @@ -25,6 +25,7 @@ import android.content.Context import android.content.Intent import android.content.res.Configuration import android.os.Bundle +import android.os.Process.INVALID_UID import android.text.TextUtils import android.util.Log import android.view.Gravity @@ -47,6 +48,7 @@ import com.android.systemui.controls.ui.ControlsActivity import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.res.R import com.android.systemui.settings.UserTracker +import com.android.systemui.utils.SafeIconLoader import java.text.Collator import java.util.concurrent.Executor import javax.inject.Inject @@ -57,6 +59,8 @@ constructor( @Main private val executor: Executor, private val controller: ControlsControllerImpl, private val userTracker: UserTracker, + private val safeIconLoaderFactory: SafeIconLoader.Factory, + private val controlsListingController: ControlsListingController, ) : ComponentActivity(), ControlsManagementActivity { companion object { @@ -196,9 +200,20 @@ constructor( listOfStructures = listOf(listOfStructures[structureIndex]) } + val uid = + controlsListingController + .getCurrentServices() + .firstOrNull { it.componentName == componentName } + ?.serviceInfo + ?.applicationInfo + ?.uid ?: INVALID_UID + val packageName = componentName.packageName + val safeIconLoader = + safeIconLoaderFactory.create(uid, packageName, userTracker.userId) + executor.execute { structurePager.adapter = - StructureAdapter(listOfStructures, userTracker.userId) + StructureAdapter(listOfStructures, userTracker.userId, safeIconLoader) structurePager.setCurrentItem(structureIndex) if (error) { statusText.text = @@ -260,8 +275,18 @@ constructor( private fun setUpPager() { structurePager.alpha = 0.0f pageIndicator.alpha = 0.0f + val uid = + controlsListingController + .getCurrentServices() + .firstOrNull { it.componentName == component } + ?.serviceInfo + ?.applicationInfo + ?.uid ?: INVALID_UID + val packageName = componentName?.packageName ?: "" + val safeIconLoader = safeIconLoaderFactory.create(uid, packageName, userTracker.userId) + structurePager.apply { - adapter = StructureAdapter(emptyList(), userTracker.userId) + adapter = StructureAdapter(emptyList(), userTracker.userId, safeIconLoader) registerOnPageChangeCallback( object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt index 7e56077dec29..dc6f3c7a514b 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt @@ -22,10 +22,12 @@ import android.view.ViewGroup import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.android.systemui.res.R +import com.android.systemui.utils.SafeIconLoader class StructureAdapter( private val models: List<StructureContainer>, private val currentUserId: Int, + private val safeIconLoader: SafeIconLoader, ) : RecyclerView.Adapter<StructureAdapter.StructureHolder>() { override fun onCreateViewHolder(parent: ViewGroup, p1: Int): StructureHolder { @@ -33,6 +35,7 @@ class StructureAdapter( return StructureHolder( layoutInflater.inflate(R.layout.controls_structure_page, parent, false), currentUserId, + safeIconLoader, ) } @@ -42,8 +45,8 @@ class StructureAdapter( holder.bind(models[index].model) } - class StructureHolder(view: View, currentUserId: Int) : - RecyclerView.ViewHolder(view) { + class StructureHolder(view: View, currentUserId: Int, safeIconLoader: SafeIconLoader) : + RecyclerView.ViewHolder(view) { private val recyclerView: RecyclerView private val controlAdapter: ControlAdapter @@ -51,7 +54,7 @@ class StructureAdapter( init { recyclerView = itemView.requireViewById<RecyclerView>(R.id.listAll) val elevation = itemView.context.resources.getFloat(R.dimen.control_card_elevation) - controlAdapter = ControlAdapter(elevation, currentUserId) + controlAdapter = ControlAdapter(elevation, currentUserId, safeIconLoader) setUpRecyclerView() } @@ -60,23 +63,29 @@ class StructureAdapter( } private fun setUpRecyclerView() { - val margin = itemView.context.resources - .getDimensionPixelSize(R.dimen.controls_card_margin) + val margin = + itemView.context.resources.getDimensionPixelSize(R.dimen.controls_card_margin) val itemDecorator = MarginItemDecorator(margin, margin) val spanCount = ControlAdapter.findMaxColumns(itemView.resources) recyclerView.apply { this.adapter = controlAdapter - layoutManager = GridLayoutManager(recyclerView.context, spanCount).apply { - spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { - override fun getSpanSize(position: Int): Int { - return if (adapter?.getItemViewType(position) - != ControlAdapter.TYPE_CONTROL) spanCount else 1 - } + layoutManager = + GridLayoutManager(recyclerView.context, spanCount).apply { + spanSizeLookup = + object : GridLayoutManager.SpanSizeLookup() { + override fun getSpanSize(position: Int): Int { + return if ( + adapter?.getItemViewType(position) != + ControlAdapter.TYPE_CONTROL + ) + spanCount + else 1 + } + } } - } addItemDecoration(itemDecorator) } } } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt index fdb9971a7d63..5e09b7f03822 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt @@ -48,12 +48,13 @@ import android.widget.ImageView import android.widget.TextView import androidx.annotation.ColorInt import androidx.annotation.VisibleForTesting -import com.android.internal.graphics.ColorUtils -import com.android.systemui.res.R import com.android.app.animation.Interpolators +import com.android.internal.graphics.ColorUtils import com.android.systemui.controls.ControlsMetricsLogger import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.res.R import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.utils.SafeIconLoader import java.util.function.Supplier /** @@ -70,6 +71,7 @@ class ControlViewHolder( val controlsMetricsLogger: ControlsMetricsLogger, val uid: Int, val currentUserId: Int, + val safeIconLoader: SafeIconLoader, ) { companion object { @@ -78,10 +80,8 @@ class ControlViewHolder( private const val ALPHA_DISABLED = 0 private const val STATUS_ALPHA_ENABLED = 1f private const val STATUS_ALPHA_DIMMED = 0.45f - private val FORCE_PANEL_DEVICES = setOf( - DeviceTypes.TYPE_THERMOSTAT, - DeviceTypes.TYPE_CAMERA - ) + private val FORCE_PANEL_DEVICES = + setOf(DeviceTypes.TYPE_THERMOSTAT, DeviceTypes.TYPE_CAMERA) private val ATTR_ENABLED = intArrayOf(android.R.attr.state_enabled) private val ATTR_DISABLED = intArrayOf(-android.R.attr.state_enabled) const val MIN_LEVEL = 0 @@ -89,8 +89,8 @@ class ControlViewHolder( } private val canUseIconPredicate = CanUseIconPredicate(currentUserId) - private val toggleBackgroundIntensity: Float = layout.context.resources - .getFraction(R.fraction.controls_toggle_bg_intensity, 1, 1) + private val toggleBackgroundIntensity: Float = + layout.context.resources.getFraction(R.fraction.controls_toggle_bg_intensity, 1, 1) private var stateAnimator: ValueAnimator? = null private var statusAnimator: Animator? = null private val baseLayer: GradientDrawable @@ -112,8 +112,10 @@ class ControlViewHolder( val deviceType: Int get() = cws.control?.let { it.deviceType } ?: cws.ci.deviceType + val controlStatus: Int get() = cws.control?.let { it.status } ?: Control.STATUS_UNKNOWN + val controlTemplate: ControlTemplate get() = cws.control?.let { it.controlTemplate } ?: ControlTemplate.NO_TEMPLATE @@ -129,14 +131,15 @@ class ControlViewHolder( } fun findBehaviorClass( - status: Int, - template: ControlTemplate, - deviceType: Int + status: Int, + template: ControlTemplate, + deviceType: Int, ): Supplier<out Behavior> { return when { status != Control.STATUS_OK -> Supplier { StatusBehavior() } template == ControlTemplate.NO_TEMPLATE -> Supplier { TouchBehavior() } - template is ThumbnailTemplate -> Supplier { ThumbnailBehavior(currentUserId) } + template is ThumbnailTemplate -> + Supplier { ThumbnailBehavior(currentUserId, safeIconLoader) } // Required for legacy support, or where cameras do not use the new template deviceType == DeviceTypes.TYPE_CAMERA -> Supplier { TouchBehavior() } @@ -172,18 +175,20 @@ class ControlViewHolder( cws.control?.let { layout.setClickable(true) - layout.setOnLongClickListener(View.OnLongClickListener() { - controlActionCoordinator.longPress(this@ControlViewHolder) - true - }) + layout.setOnLongClickListener( + View.OnLongClickListener() { + controlActionCoordinator.longPress(this@ControlViewHolder) + true + } + ) controlActionCoordinator.runPendingAction(cws.ci.controlId) } val wasLoading = isLoading isLoading = false - behavior = bindBehavior(behavior, - findBehaviorClass(controlStatus, controlTemplate, deviceType)) + behavior = + bindBehavior(behavior, findBehaviorClass(controlStatus, controlTemplate, deviceType)) updateContentDescription() // Only log one event per control, at the moment we have determined that the control @@ -198,8 +203,7 @@ class ControlViewHolder( // OK responses signal normal behavior, and the app will provide control updates val failedAttempt = lastChallengeDialog != null when (response) { - ControlAction.RESPONSE_OK -> - lastChallengeDialog = null + ControlAction.RESPONSE_OK -> lastChallengeDialog = null ControlAction.RESPONSE_UNKNOWN -> { lastChallengeDialog = null setErrorStatus() @@ -209,18 +213,28 @@ class ControlViewHolder( setErrorStatus() } ControlAction.RESPONSE_CHALLENGE_PIN -> { - lastChallengeDialog = ChallengeDialogs.createPinDialog( - this, false /* useAlphanumeric */, failedAttempt, onDialogCancel) + lastChallengeDialog = + ChallengeDialogs.createPinDialog( + this, + false /* useAlphanumeric */, + failedAttempt, + onDialogCancel, + ) lastChallengeDialog?.show() } ControlAction.RESPONSE_CHALLENGE_PASSPHRASE -> { - lastChallengeDialog = ChallengeDialogs.createPinDialog( - this, true /* useAlphanumeric */, failedAttempt, onDialogCancel) + lastChallengeDialog = + ChallengeDialogs.createPinDialog( + this, + true /* useAlphanumeric */, + failedAttempt, + onDialogCancel, + ) lastChallengeDialog?.show() } ControlAction.RESPONSE_CHALLENGE_ACK -> { - lastChallengeDialog = ChallengeDialogs.createConfirmationDialog( - this, onDialogCancel) + lastChallengeDialog = + ChallengeDialogs.createConfirmationDialog(this, onDialogCancel) lastChallengeDialog?.show() } } @@ -235,9 +249,7 @@ class ControlViewHolder( fun setErrorStatus() { val text = context.resources.getString(R.string.controls_error_failed) - animateStatusChange(/* animated */ true, { - setStatusText(text, /* immediately */ true) - }) + animateStatusChange(/* animated */ true, { setStatusText(text, /* immediately */ true) }) } private fun updateContentDescription() = @@ -256,34 +268,32 @@ class ControlViewHolder( fun bindBehavior( existingBehavior: Behavior?, supplier: Supplier<out Behavior>, - offset: Int = 0 + offset: Int = 0, ): Behavior { val newBehavior = supplier.get() - val behavior = if (existingBehavior == null || - existingBehavior::class != newBehavior::class) { - // Behavior changes can signal a change in template from the app or - // first time setup - newBehavior.initialize(this) - - // let behaviors define their own, if necessary, and clear any existing ones - layout.setAccessibilityDelegate(null) - newBehavior - } else { - existingBehavior - } + val behavior = + if (existingBehavior == null || existingBehavior::class != newBehavior::class) { + // Behavior changes can signal a change in template from the app or + // first time setup + newBehavior.initialize(this) + + // let behaviors define their own, if necessary, and clear any existing ones + layout.setAccessibilityDelegate(null) + newBehavior + } else { + existingBehavior + } - return behavior.also { - it.bind(cws, offset) - } + return behavior.also { it.bind(cws, offset) } } internal fun applyRenderInfo(enabled: Boolean, offset: Int, animated: Boolean = true) { - val deviceTypeOrError = if (controlStatus == Control.STATUS_OK || - controlStatus == Control.STATUS_UNKNOWN) { - deviceType - } else { - RenderInfo.ERROR_ICON - } + val deviceTypeOrError = + if (controlStatus == Control.STATUS_OK || controlStatus == Control.STATUS_UNKNOWN) { + deviceType + } else { + RenderInfo.ERROR_ICON + } val ri = RenderInfo.lookup(context, cws.componentName, deviceTypeOrError, offset) val fg = context.resources.getColorStateList(ri.foreground, context.theme) val newText = nextStatusText @@ -317,28 +327,31 @@ class ControlViewHolder( private fun animateBackgroundChange( animated: Boolean, enabled: Boolean, - @ColorRes bgColor: Int + @ColorRes bgColor: Int, ) { val bg = context.resources.getColor(R.color.control_default_background, context.theme) - val (newClipColor, newAlpha) = if (enabled) { - // allow color overrides for the enabled state only - val color = cws.control?.getCustomColor()?.let { - val state = intArrayOf(android.R.attr.state_enabled) - it.getColorForState(state, it.getDefaultColor()) - } ?: context.resources.getColor(bgColor, context.theme) - listOf(color, ALPHA_ENABLED) - } else { - listOf( - context.resources.getColor(R.color.control_default_background, context.theme), - ALPHA_DISABLED - ) - } - val newBaseColor = if (behavior is ToggleRangeBehavior) { - ColorUtils.blendARGB(bg, newClipColor, toggleBackgroundIntensity) - } else { - bg - } + val (newClipColor, newAlpha) = + if (enabled) { + // allow color overrides for the enabled state only + val color = + cws.control?.getCustomColor()?.let { + val state = intArrayOf(android.R.attr.state_enabled) + it.getColorForState(state, it.getDefaultColor()) + } ?: context.resources.getColor(bgColor, context.theme) + listOf(color, ALPHA_ENABLED) + } else { + listOf( + context.resources.getColor(R.color.control_default_background, context.theme), + ALPHA_DISABLED, + ) + } + val newBaseColor = + if (behavior is ToggleRangeBehavior) { + ColorUtils.blendARGB(bg, newClipColor, toggleBackgroundIntensity) + } else { + bg + } clipLayer.drawable?.apply { clipLayer.alpha = ALPHA_DISABLED @@ -347,7 +360,11 @@ class ControlViewHolder( startBackgroundAnimation(this, newAlpha, newClipColor, newBaseColor) } else { applyBackgroundChange( - this, newAlpha, newClipColor, newBaseColor, newLayoutAlpha = 1f + this, + newAlpha, + newClipColor, + newBaseColor, + newLayoutAlpha = 1f, ) } } @@ -357,41 +374,45 @@ class ControlViewHolder( clipDrawable: Drawable, newAlpha: Int, @ColorInt newClipColor: Int, - @ColorInt newBaseColor: Int + @ColorInt newBaseColor: Int, ) { - val oldClipColor = if (clipDrawable is GradientDrawable) { - clipDrawable.color?.defaultColor ?: newClipColor - } else { - newClipColor - } + val oldClipColor = + if (clipDrawable is GradientDrawable) { + clipDrawable.color?.defaultColor ?: newClipColor + } else { + newClipColor + } val oldBaseColor = baseLayer.color?.defaultColor ?: newBaseColor val oldAlpha = layout.alpha - stateAnimator = ValueAnimator.ofInt(clipLayer.alpha, newAlpha).apply { - addUpdateListener { - val updatedAlpha = it.animatedValue as Int - val updatedClipColor = ColorUtils.blendARGB(oldClipColor, newClipColor, - it.animatedFraction) - val updatedBaseColor = ColorUtils.blendARGB(oldBaseColor, newBaseColor, - it.animatedFraction) - val updatedLayoutAlpha = MathUtils.lerp(oldAlpha, 1f, it.animatedFraction) - applyBackgroundChange( + stateAnimator = + ValueAnimator.ofInt(clipLayer.alpha, newAlpha).apply { + addUpdateListener { + val updatedAlpha = it.animatedValue as Int + val updatedClipColor = + ColorUtils.blendARGB(oldClipColor, newClipColor, it.animatedFraction) + val updatedBaseColor = + ColorUtils.blendARGB(oldBaseColor, newBaseColor, it.animatedFraction) + val updatedLayoutAlpha = MathUtils.lerp(oldAlpha, 1f, it.animatedFraction) + applyBackgroundChange( clipDrawable, updatedAlpha, updatedClipColor, updatedBaseColor, - updatedLayoutAlpha + updatedLayoutAlpha, + ) + } + addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + stateAnimator = null + } + } ) + duration = STATE_ANIMATION_DURATION + interpolator = Interpolators.CONTROL_STATE + start() } - addListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - stateAnimator = null - } - }) - duration = STATE_ANIMATION_DURATION - interpolator = Interpolators.CONTROL_STATE - start() - } } /** @@ -405,7 +426,7 @@ class ControlViewHolder( newAlpha: Int, @ColorInt newClipColor: Int, @ColorInt newBaseColor: Int, - newLayoutAlpha: Float + newLayoutAlpha: Float, ) { clipDrawable.alpha = newAlpha if (clipDrawable is GradientDrawable) { @@ -425,38 +446,46 @@ class ControlViewHolder( if (isLoading) { statusRowUpdater.invoke() - statusAnimator = ObjectAnimator.ofFloat(status, "alpha", STATUS_ALPHA_DIMMED).apply { - repeatMode = ValueAnimator.REVERSE - repeatCount = ValueAnimator.INFINITE - duration = 500L - interpolator = Interpolators.LINEAR - startDelay = 900L - start() - } + statusAnimator = + ObjectAnimator.ofFloat(status, "alpha", STATUS_ALPHA_DIMMED).apply { + repeatMode = ValueAnimator.REVERSE + repeatCount = ValueAnimator.INFINITE + duration = 500L + interpolator = Interpolators.LINEAR + startDelay = 900L + start() + } } else { - val fadeOut = ObjectAnimator.ofFloat(status, "alpha", 0f).apply { - duration = 200L - interpolator = Interpolators.LINEAR - addListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - statusRowUpdater.invoke() - } - }) - } - val fadeIn = ObjectAnimator.ofFloat(status, "alpha", STATUS_ALPHA_ENABLED).apply { - duration = 200L - interpolator = Interpolators.LINEAR - } - statusAnimator = AnimatorSet().apply { - playSequentially(fadeOut, fadeIn) - addListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - status.alpha = STATUS_ALPHA_ENABLED - statusAnimator = null - } - }) - start() - } + val fadeOut = + ObjectAnimator.ofFloat(status, "alpha", 0f).apply { + duration = 200L + interpolator = Interpolators.LINEAR + addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + statusRowUpdater.invoke() + } + } + ) + } + val fadeIn = + ObjectAnimator.ofFloat(status, "alpha", STATUS_ALPHA_ENABLED).apply { + duration = 200L + interpolator = Interpolators.LINEAR + } + statusAnimator = + AnimatorSet().apply { + playSequentially(fadeOut, fadeIn) + addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + status.alpha = STATUS_ALPHA_ENABLED + statusAnimator = null + } + } + ) + start() + } } } @@ -466,7 +495,7 @@ class ControlViewHolder( text: CharSequence, drawable: Drawable, color: ColorStateList, - control: Control? + control: Control?, ) { setEnabled(enabled) @@ -475,29 +504,30 @@ class ControlViewHolder( status.setTextColor(color) - control?.customIcon - ?.takeIf(canUseIconPredicate) - ?.let { - icon.setImageIcon(it) + control?.customIcon?.takeIf(canUseIconPredicate)?.let { it -> + val loadedDrawable = safeIconLoader.load(it) + icon.setImageDrawable(loadedDrawable) icon.imageTintList = it.tintList - } ?: run { - if (drawable is StateListDrawable) { - // Only reset the drawable if it is a different resource, as it will interfere - // with the image state and animation. - if (icon.drawable == null || !(icon.drawable is StateListDrawable)) { + loadedDrawable + } + ?: run { + if (drawable is StateListDrawable) { + // Only reset the drawable if it is a different resource, as it will interfere + // with the image state and animation. + if (icon.drawable == null || !(icon.drawable is StateListDrawable)) { + icon.setImageDrawable(drawable) + } + val state = if (enabled) ATTR_ENABLED else ATTR_DISABLED + icon.setImageState(state, true) + } else { icon.setImageDrawable(drawable) } - val state = if (enabled) ATTR_ENABLED else ATTR_DISABLED - icon.setImageState(state, true) - } else { - icon.setImageDrawable(drawable) - } - // do not color app icons - if (deviceType != DeviceTypes.TYPE_ROUTINE) { - icon.imageTintList = color + // do not color app icons + if (deviceType != DeviceTypes.TYPE_ROUTINE) { + icon.imageTintList = color + } } - } chevronIcon.imageTintList = icon.imageTintList } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index 8831dc61e452..66bfa986901d 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -52,7 +52,6 @@ import android.widget.Space import android.widget.TextView import androidx.annotation.VisibleForTesting import com.android.systemui.Dumpable -import com.android.systemui.res.R import com.android.systemui.controls.ControlsMetricsLogger import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.CustomIconCache @@ -74,11 +73,13 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.flags.FeatureFlags import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.res.R import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.asIndenting import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.withIncreasedIndent +import com.android.systemui.utils.SafeIconLoader import com.android.wm.shell.taskview.TaskViewFactory import dagger.Lazy import java.io.PrintWriter @@ -90,26 +91,29 @@ import javax.inject.Inject private data class ControlKey(val componentName: ComponentName, val controlId: String) @SysUISingleton -class ControlsUiControllerImpl @Inject constructor ( - val controlsController: Lazy<ControlsController>, - val context: Context, - private val packageManager: PackageManager, - @Main val uiExecutor: DelayableExecutor, - @Background val bgExecutor: DelayableExecutor, - val controlsListingController: Lazy<ControlsListingController>, - private val controlActionCoordinator: ControlActionCoordinator, - private val activityStarter: ActivityStarter, - private val iconCache: CustomIconCache, - private val controlsMetricsLogger: ControlsMetricsLogger, - private val keyguardStateController: KeyguardStateController, - private val userTracker: UserTracker, - private val taskViewFactory: Optional<TaskViewFactory>, - private val controlsSettingsRepository: ControlsSettingsRepository, - private val authorizedPanelsRepository: AuthorizedPanelsRepository, - private val selectedComponentRepository: SelectedComponentRepository, - private val featureFlags: FeatureFlags, - private val dialogsFactory: ControlsDialogsFactory, - dumpManager: DumpManager +class ControlsUiControllerImpl +@Inject +constructor( + val controlsController: Lazy<ControlsController>, + val context: Context, + private val packageManager: PackageManager, + @Main val uiExecutor: DelayableExecutor, + @Background val bgExecutor: DelayableExecutor, + val controlsListingController: Lazy<ControlsListingController>, + private val controlActionCoordinator: ControlActionCoordinator, + private val activityStarter: ActivityStarter, + private val iconCache: CustomIconCache, + private val controlsMetricsLogger: ControlsMetricsLogger, + private val keyguardStateController: KeyguardStateController, + private val userTracker: UserTracker, + private val taskViewFactory: Optional<TaskViewFactory>, + private val controlsSettingsRepository: ControlsSettingsRepository, + private val authorizedPanelsRepository: AuthorizedPanelsRepository, + private val selectedComponentRepository: SelectedComponentRepository, + private val featureFlags: FeatureFlags, + private val safeIconLoaderFactory: SafeIconLoader.Factory, + private val dialogsFactory: ControlsDialogsFactory, + dumpManager: DumpManager, ) : ControlsUiController, Dumpable { companion object { @@ -139,26 +143,26 @@ class ControlsUiControllerImpl @Inject constructor ( private var taskViewController: PanelTaskViewController? = null private val collator = Collator.getInstance(context.resources.configuration.locales[0]) - private val localeComparator = compareBy<SelectionItem, CharSequence>(collator) { - it.getTitle() - } + private val localeComparator = + compareBy<SelectionItem, CharSequence>(collator) { it.getTitle() } private var openAppIntent: Intent? = null private var overflowMenuAdapter: BaseAdapter? = null private var removeAppDialog: Dialog? = null - private val onSeedingComplete = Consumer<Boolean> { - accepted -> + private val onSeedingComplete = + Consumer<Boolean> { accepted -> if (accepted) { - selectedItem = controlsController.get().getFavorites().maxByOrNull { - it.controls.size - }?.let { - SelectedItem.StructureItem(it) - } ?: SelectedItem.EMPTY_SELECTION + selectedItem = + controlsController + .get() + .getFavorites() + .maxByOrNull { it.controls.size } + ?.let { SelectedItem.StructureItem(it) } ?: SelectedItem.EMPTY_SELECTION updatePreferences(selectedItem) } reload(parent) - } + } private lateinit var activityContext: Context private lateinit var listingCallback: ControlsListingController.ControlsListingCallback @@ -176,10 +180,11 @@ class ControlsUiControllerImpl @Inject constructor ( return object : ControlsListingController.ControlsListingCallback { override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) { val authorizedPanels = authorizedPanelsRepository.getAuthorizedPanels() - val lastItems = serviceInfos.map { - val uid = it.serviceInfo.applicationInfo.uid + val lastItems = + serviceInfos.map { + val uid = it.serviceInfo.applicationInfo.uid - SelectionItem( + SelectionItem( it.loadLabel(), "", it.loadIcon(), @@ -189,9 +194,9 @@ class ControlsUiControllerImpl @Inject constructor ( it.panelActivity } else { null - } - ) - } + }, + ) + } uiExecutor.execute { parent.removeAllViews() if (lastItems.size > 0) { @@ -205,8 +210,8 @@ class ControlsUiControllerImpl @Inject constructor ( override fun resolveActivity(): Class<*> { val allStructures = controlsController.get().getFavorites() val selected = getPreferredSelectedItem(allStructures) - val anyPanels = controlsListingController.get().getCurrentServices() - .any { it.panelActivity != null } + val anyPanels = + controlsListingController.get().getCurrentServices().any { it.panelActivity != null } return if (controlsController.get().addSeedingFavoritesCallback(onSeedingComplete)) { ControlsActivity::class.java @@ -217,11 +222,7 @@ class ControlsUiControllerImpl @Inject constructor ( } } - override fun show( - parent: ViewGroup, - onDismiss: Runnable, - activityContext: Context - ) { + override fun show(parent: ViewGroup, onDismiss: Runnable, activityContext: Context) { Log.d(ControlsUiController.TAG, "show()") Trace.instant(Trace.TRACE_TAG_APP, "ControlsUiControllerImpl#show") this.parent = parent @@ -241,7 +242,7 @@ class ControlsUiControllerImpl @Inject constructor ( if (controlsController.get().addSeedingFavoritesCallback(onSeedingComplete)) { listingCallback = createCallback(::showSeedingView) } else if ( - selectedItem !is SelectedItem.PanelItem && + selectedItem !is SelectedItem.PanelItem && !selectedItem.hasControls && allStructures.size <= 1 ) { @@ -250,11 +251,11 @@ class ControlsUiControllerImpl @Inject constructor ( } else { val selected = selectedItem if (selected is SelectedItem.StructureItem) { - selected.structure.controls.map { - ControlWithState(selected.structure.componentName, it, null) - }.associateByTo(controlsById) { - ControlKey(selected.structure.componentName, it.ci.controlId) - } + selected.structure.controls + .map { ControlWithState(selected.structure.componentName, it, null) } + .associateByTo(controlsById) { + ControlKey(selected.structure.componentName, it.ci.controlId) + } controlsController.get().subscribeToFavorites(selected.structure) } else { controlsController.get().bindComponentForPanel(selected.componentName) @@ -285,18 +286,20 @@ class ControlsUiControllerImpl @Inject constructor ( val fadeAnim = ObjectAnimator.ofFloat(parent, "alpha", 1.0f, 0.0f) fadeAnim.setInterpolator(AccelerateInterpolator(1.0f)) fadeAnim.setDuration(FADE_IN_MILLIS) - fadeAnim.addListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - controlViewsById.clear() - controlsById.clear() - - show(parent, onDismiss, activityContext) - val showAnim = ObjectAnimator.ofFloat(parent, "alpha", 0.0f, 1.0f) - showAnim.setInterpolator(DecelerateInterpolator(1.0f)) - showAnim.setDuration(FADE_IN_MILLIS) - showAnim.start() + fadeAnim.addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + controlViewsById.clear() + controlsById.clear() + + show(parent, onDismiss, activityContext) + val showAnim = ObjectAnimator.ofFloat(parent, "alpha", 0.0f, 1.0f) + showAnim.setInterpolator(DecelerateInterpolator(1.0f)) + showAnim.setDuration(FADE_IN_MILLIS) + showAnim.start() + } } - }) + ) fadeAnim.start() } @@ -321,39 +324,48 @@ class ControlsUiControllerImpl @Inject constructor ( } private fun startDefaultActivity() { - openAppIntent?.let { - startActivity(it, animateExtra = false) - } + openAppIntent?.let { startActivity(it, animateExtra = false) } } @VisibleForTesting internal fun startRemovingApp(componentName: ComponentName, appName: CharSequence) { - activityStarter.dismissKeyguardThenExecute({ - showAppRemovalDialog(componentName, appName) - true - }, null, true) + activityStarter.dismissKeyguardThenExecute( + { + showAppRemovalDialog(componentName, appName) + true + }, + null, + true, + ) } private fun showAppRemovalDialog(componentName: ComponentName, appName: CharSequence) { removeAppDialog?.cancel() - removeAppDialog = dialogsFactory.createRemoveAppDialog(context, appName) { shouldRemove -> - if (!shouldRemove || !controlsController.get().removeFavorites(componentName)) { - return@createRemoveAppDialog - } + removeAppDialog = + dialogsFactory + .createRemoveAppDialog(context, appName) { shouldRemove -> + if (!shouldRemove || !controlsController.get().removeFavorites(componentName)) { + return@createRemoveAppDialog + } - if (selectedComponentRepository.getSelectedComponent()?.componentName == - componentName) { - selectedComponentRepository.removeSelectedComponent() - } + if ( + selectedComponentRepository.getSelectedComponent()?.componentName == + componentName + ) { + selectedComponentRepository.removeSelectedComponent() + } - val selectedItem = getPreferredSelectedItem(controlsController.get().getFavorites()) - if (selectedItem == SelectedItem.EMPTY_SELECTION) { - // User removed the last panel. In this case we start app selection flow and don't - // want to auto-add it again - selectedComponentRepository.setShouldAddDefaultComponent(false) - } - reload(parent) - }.apply { show() } + val selectedItem = + getPreferredSelectedItem(controlsController.get().getFavorites()) + if (selectedItem == SelectedItem.EMPTY_SELECTION) { + // User removed the last panel. In this case we start app selection flow and + // don't + // want to auto-add it again + selectedComponentRepository.setShouldAddDefaultComponent(false) + } + reload(parent) + } + .apply { show() } } private fun startTargetedActivity(si: StructureInfo, klazz: Class<*>) { @@ -366,8 +378,10 @@ class ControlsUiControllerImpl @Inject constructor ( private fun putIntentExtras(intent: Intent, si: StructureInfo) { intent.apply { - putExtra(ControlsFavoritingActivity.EXTRA_APP, - controlsListingController.get().getAppLabel(si.componentName)) + putExtra( + ControlsFavoritingActivity.EXTRA_APP, + controlsListingController.get().getAppLabel(si.componentName), + ) putExtra(ControlsFavoritingActivity.EXTRA_STRUCTURE, si.structure) putExtra(Intent.EXTRA_COMPONENT_NAME, si.componentName) } @@ -390,7 +404,7 @@ class ControlsUiControllerImpl @Inject constructor ( } else { activityContext.startActivity( intent, - ActivityOptions.makeSceneTransitionAnimation(activityContext as Activity).toBundle() + ActivityOptions.makeSceneTransitionAnimation(activityContext as Activity).toBundle(), ) } } @@ -401,8 +415,8 @@ class ControlsUiControllerImpl @Inject constructor ( val (panels, structures) = items.partition { it.isPanel } val panelComponents = panels.map { it.componentName }.toSet() - val itemsByComponent = structures.associateBy { it.componentName } - .filterNot { it.key in panelComponents } + val itemsByComponent = + structures.associateBy { it.componentName }.filterNot { it.key in panelComponents } val panelsAndStructures = mutableListOf<SelectionItem>() allStructures.mapNotNullTo(panelsAndStructures) { itemsByComponent.get(it.componentName)?.copy(structure = it.structure) @@ -413,7 +427,8 @@ class ControlsUiControllerImpl @Inject constructor ( lastSelections = panelsAndStructures - val selectionItem = findSelectionItem(selectedItem, panelsAndStructures) + val selectionItem = + findSelectionItem(selectedItem, panelsAndStructures) ?: if (panels.isNotEmpty()) { // If we couldn't find a good selected item, but there's at least one panel, // show a panel. @@ -428,8 +443,10 @@ class ControlsUiControllerImpl @Inject constructor ( if (taskViewFactory.isPresent && selectionItem.isPanel) { createPanelView(selectionItem.panelComponentName!!) } else if (!selectionItem.isPanel) { - controlsMetricsLogger - .refreshBegin(selectionItem.uid, !keyguardStateController.isUnlocked()) + controlsMetricsLogger.refreshBegin( + selectionItem.uid, + !keyguardStateController.isUnlocked(), + ) createListView(selectionItem) } else { Log.w(ControlsUiController.TAG, "Not TaskViewFactory to display panel $selectionItem") @@ -437,176 +454,200 @@ class ControlsUiControllerImpl @Inject constructor ( this.selectionItem = selectionItem bgExecutor.execute { - val intent = Intent(Intent.ACTION_MAIN) + val intent = + Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) .setPackage(selectionItem.componentName.packageName) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or - Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) - val intents = packageManager - .queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(0L)) - intents.firstOrNull { it.activityInfo.exported }?.let { resolved -> - intent.setPackage(null) - intent.setComponent(resolved.activityInfo.componentName) - openAppIntent = intent - parent.post { - // This will call show on the PopupWindow in the same thread, so make sure this - // happens in the view thread. - overflowMenuAdapter?.notifyDataSetChanged() + .addFlags( + Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED + ) + val intents = + packageManager.queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(0L)) + intents + .firstOrNull { it.activityInfo.exported } + ?.let { resolved -> + intent.setPackage(null) + intent.setComponent(resolved.activityInfo.componentName) + openAppIntent = intent + parent.post { + // This will call show on the PopupWindow in the same thread, so make sure + // this + // happens in the view thread. + overflowMenuAdapter?.notifyDataSetChanged() + } } - } } createDropDown(panelsAndStructures, selectionItem) val currentApps = panelsAndStructures.map { it.componentName }.toSet() - val allApps = controlsListingController.get() - .getCurrentServices().map { it.componentName }.toSet() - createMenu( - selectionItem = selectionItem, - extraApps = (allApps - currentApps).isNotEmpty(), - ) + val allApps = + controlsListingController.get().getCurrentServices().map { it.componentName }.toSet() + createMenu(selectionItem = selectionItem, extraApps = (allApps - currentApps).isNotEmpty()) } private fun createPanelView(componentName: ComponentName) { - val setting = controlsSettingsRepository - .allowActionOnTrivialControlsInLockscreen.value - val pendingIntent = PendingIntent.getActivityAsUser( + val setting = controlsSettingsRepository.allowActionOnTrivialControlsInLockscreen.value + val pendingIntent = + PendingIntent.getActivityAsUser( context, 0, Intent().apply { component = componentName putExtra( ControlsProviderService.EXTRA_LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, - setting + setting, ) if (homePanelDream()) { - putExtra(ControlsProviderService.EXTRA_CONTROLS_SURFACE, - ControlsProviderService.CONTROLS_SURFACE_ACTIVITY_PANEL) + putExtra( + ControlsProviderService.EXTRA_CONTROLS_SURFACE, + ControlsProviderService.CONTROLS_SURFACE_ACTIVITY_PANEL, + ) } }, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT, ActivityOptions.makeBasic() .setPendingIntentCreatorBackgroundActivityStartMode( - ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle(), - userTracker.userHandle - ) + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED + ) + .toBundle(), + userTracker.userHandle, + ) parent.requireViewById<View>(R.id.controls_scroll_view).visibility = View.GONE val container = parent.requireViewById<FrameLayout>(R.id.controls_panel) container.visibility = View.VISIBLE container.post { taskViewFactory.get().create(activityContext, uiExecutor) { taskView -> - taskViewController = PanelTaskViewController( - activityContext, - uiExecutor, - pendingIntent, - taskView, - onDismiss::run - ).also { - container.addView(taskView) - it.launchTaskView() - } + taskViewController = + PanelTaskViewController( + activityContext, + uiExecutor, + pendingIntent, + taskView, + onDismiss::run, + ) + .also { + container.addView(taskView) + it.launchTaskView() + } } } } private fun createMenu(selectionItem: SelectionItem, extraApps: Boolean) { val isPanel = selectedItem is SelectedItem.PanelItem - val selectedStructure = (selectedItem as? SelectedItem.StructureItem)?.structure - ?: EMPTY_STRUCTURE + val selectedStructure = + (selectedItem as? SelectedItem.StructureItem)?.structure ?: EMPTY_STRUCTURE val items = buildList { - add(OverflowMenuAdapter.MenuItem( + add( + OverflowMenuAdapter.MenuItem( context.getText(R.string.controls_open_app), - OPEN_APP_ID - )) + OPEN_APP_ID, + ) + ) if (extraApps) { - add(OverflowMenuAdapter.MenuItem( + add( + OverflowMenuAdapter.MenuItem( context.getText(R.string.controls_menu_add_another_app), - ADD_APP_ID - )) + ADD_APP_ID, + ) + ) } - add(OverflowMenuAdapter.MenuItem( + add( + OverflowMenuAdapter.MenuItem( context.getText(R.string.controls_menu_remove), REMOVE_APP_ID, - )) + ) + ) if (!isPanel) { - add(OverflowMenuAdapter.MenuItem( + add( + OverflowMenuAdapter.MenuItem( context.getText(R.string.controls_menu_edit), - EDIT_CONTROLS_ID - )) + EDIT_CONTROLS_ID, + ) + ) } } - val adapter = OverflowMenuAdapter(context, R.layout.controls_more_item, items) { position -> + val adapter = + OverflowMenuAdapter(context, R.layout.controls_more_item, items) { position -> getItemId(position) != OPEN_APP_ID || openAppIntent != null - } + } val anchor = parent.requireViewById<ImageView>(R.id.controls_more) - anchor.setOnClickListener(object : View.OnClickListener { - override fun onClick(v: View) { - popup = ControlsPopupMenu(popupThemedContext).apply { - width = ViewGroup.LayoutParams.WRAP_CONTENT - anchorView = anchor - setDropDownGravity(Gravity.END) - setAdapter(adapter) - - setOnItemClickListener(object : AdapterView.OnItemClickListener { - override fun onItemClick( - parent: AdapterView<*>, - view: View, - pos: Int, - id: Long - ) { - when (id) { - OPEN_APP_ID -> startDefaultActivity() - ADD_APP_ID -> startProviderSelectorActivity() - ADD_CONTROLS_ID -> startFavoritingActivity(selectedStructure) - EDIT_CONTROLS_ID -> startEditingActivity(selectedStructure) - REMOVE_APP_ID -> startRemovingApp( - selectionItem.componentName, selectionItem.appName - ) - } - dismiss() + anchor.setOnClickListener( + object : View.OnClickListener { + override fun onClick(v: View) { + popup = + ControlsPopupMenu(popupThemedContext).apply { + width = ViewGroup.LayoutParams.WRAP_CONTENT + anchorView = anchor + setDropDownGravity(Gravity.END) + setAdapter(adapter) + + setOnItemClickListener( + object : AdapterView.OnItemClickListener { + override fun onItemClick( + parent: AdapterView<*>, + view: View, + pos: Int, + id: Long, + ) { + when (id) { + OPEN_APP_ID -> startDefaultActivity() + ADD_APP_ID -> startProviderSelectorActivity() + ADD_CONTROLS_ID -> + startFavoritingActivity(selectedStructure) + EDIT_CONTROLS_ID -> + startEditingActivity(selectedStructure) + REMOVE_APP_ID -> + startRemovingApp( + selectionItem.componentName, + selectionItem.appName, + ) + } + dismiss() + } + } + ) + show() + listView?.post { listView?.requestAccessibilityFocus() } } - }) - show() - listView?.post { listView?.requestAccessibilityFocus() } } } - }) + ) overflowMenuAdapter = adapter } private fun createDropDown(items: List<SelectionItem>, selected: SelectionItem) { - items.forEach { - RenderInfo.registerComponentIcon(it.componentName, it.icon) - } + items.forEach { RenderInfo.registerComponentIcon(it.componentName, it.icon) } - val adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply { - add(selected) - addAll(items - .filter { it !== selected } - .sortedBy { it.appName.toString() } - ) - } + val adapter = + ItemAdapter(context, R.layout.controls_spinner_item).apply { + add(selected) + addAll(items.filter { it !== selected }.sortedBy { it.appName.toString() }) + } - val iconSize = context.resources - .getDimensionPixelSize(R.dimen.controls_header_app_icon_size) + val iconSize = + context.resources.getDimensionPixelSize(R.dimen.controls_header_app_icon_size) /* * Default spinner widget does not work with the window type required * for this dialog. Use a textView with the ListPopupWindow to achieve * a similar effect */ - val spinner = parent.requireViewById<TextView>(R.id.app_or_structure_spinner).apply { - setText(selected.getTitle()) - // override the default color on the dropdown drawable - (getBackground() as LayerDrawable).getDrawable(0) - .setTint(context.resources.getColor(R.color.control_spinner_dropdown, null)) - selected.icon.setBounds(0, 0, iconSize, iconSize) - compoundDrawablePadding = (iconSize / 2.4f).toInt() - setCompoundDrawablesRelative(selected.icon, null, null, null) - } + val spinner = + parent.requireViewById<TextView>(R.id.app_or_structure_spinner).apply { + setText(selected.getTitle()) + // override the default color on the dropdown drawable + (getBackground() as LayerDrawable) + .getDrawable(0) + .setTint(context.resources.getColor(R.color.control_spinner_dropdown, null)) + selected.icon.setBounds(0, 0, iconSize, iconSize) + compoundDrawablePadding = (iconSize / 2.4f).toInt() + setCompoundDrawablesRelative(selected.icon, null, null, null) + } val anchor = parent.requireViewById<View>(R.id.app_or_structure_spinner) if (items.size == 1) { @@ -615,34 +656,40 @@ class ControlsUiControllerImpl @Inject constructor ( anchor.isClickable = false return } else { - spinner.background = parent.context.resources - .getDrawable(R.drawable.control_spinner_background) - } - - anchor.setOnClickListener(object : View.OnClickListener { - override fun onClick(v: View) { - popup = ControlsPopupMenu(popupThemedContext).apply { - anchorView = anchor - width = ViewGroup.LayoutParams.MATCH_PARENT - setAdapter(adapter) - - setOnItemClickListener(object : AdapterView.OnItemClickListener { - override fun onItemClick( - parent: AdapterView<*>, - view: View, - pos: Int, - id: Long - ) { - val listItem = parent.getItemAtPosition(pos) as SelectionItem - this@ControlsUiControllerImpl.switchAppOrStructure(listItem) - dismiss() + spinner.background = + parent.context.resources.getDrawable(R.drawable.control_spinner_background) + } + + anchor.setOnClickListener( + object : View.OnClickListener { + override fun onClick(v: View) { + popup = + ControlsPopupMenu(popupThemedContext).apply { + anchorView = anchor + width = ViewGroup.LayoutParams.MATCH_PARENT + setAdapter(adapter) + + setOnItemClickListener( + object : AdapterView.OnItemClickListener { + override fun onItemClick( + parent: AdapterView<*>, + view: View, + pos: Int, + id: Long, + ) { + val listItem = + parent.getItemAtPosition(pos) as SelectionItem + this@ControlsUiControllerImpl.switchAppOrStructure(listItem) + dismiss() + } + } + ) + show() + listView?.post { listView?.requestAccessibilityFocus() } } - }) - show() - listView?.post { listView?.requestAccessibilityFocus() } } } - }) + ) } private fun createControlsSpaceFrame() { @@ -658,6 +705,12 @@ class ControlsUiControllerImpl @Inject constructor ( private fun createListView(selected: SelectionItem) { if (selectedItem !is SelectedItem.StructureItem) return val selectedStructure = (selectedItem as SelectedItem.StructureItem).structure + val safeIconLoader = + safeIconLoaderFactory.create( + selected.uid, + selected.componentName.packageName, + controlsController.get().currentUserId, + ) val inflater = LayoutInflater.from(activityContext) val maxColumns = ControlAdapter.findMaxColumns(activityContext.resources) @@ -671,8 +724,8 @@ class ControlsUiControllerImpl @Inject constructor ( if (lastRow.getChildCount() == maxColumns) { lastRow = createRow(inflater, listView) } - val baseLayout = inflater.inflate( - R.layout.controls_base_item, lastRow, false) as ViewGroup + val baseLayout = + inflater.inflate(R.layout.controls_base_item, lastRow, false) as ViewGroup lastRow.addView(baseLayout) // Use ConstraintLayout in the future... for now, manually adjust margins @@ -680,16 +733,18 @@ class ControlsUiControllerImpl @Inject constructor ( val lp = baseLayout.getLayoutParams() as ViewGroup.MarginLayoutParams lp.setMarginStart(0) } - val cvh = ControlViewHolder( - baseLayout, - controlsController.get(), - uiExecutor, - bgExecutor, - controlActionCoordinator, - controlsMetricsLogger, - selected.uid, - controlsController.get().currentUserId, - ) + val cvh = + ControlViewHolder( + baseLayout, + controlsController.get(), + uiExecutor, + bgExecutor, + controlActionCoordinator, + controlsMetricsLogger, + selected.uid, + controlsController.get().currentUserId, + safeIconLoader, + ) cvh.bindData(it, false /* isLocked, will be ignored on initial load */) controlViewsById.put(key, cvh) } @@ -700,9 +755,7 @@ class ControlsUiControllerImpl @Inject constructor ( var spacersToAdd = if (mod == 0) 0 else maxColumns - mod val margin = context.resources.getDimensionPixelSize(R.dimen.control_spacing) while (spacersToAdd > 0) { - val lp = LinearLayout.LayoutParams(0, 0, 1f).apply { - setMarginStart(margin) - } + val lp = LinearLayout.LayoutParams(0, 0, 1f).apply { setMarginStart(margin) } lastRow.addView(Space(context), lp) spacersToAdd-- } @@ -715,27 +768,32 @@ class ControlsUiControllerImpl @Inject constructor ( SelectedItem.PanelItem(preferredPanel.name, component) } else { if (structures.isEmpty()) return SelectedItem.EMPTY_SELECTION - SelectedItem.StructureItem(structures.firstOrNull { - component == it.componentName && preferredPanel?.name == it.structure - } ?: structures[0]) + SelectedItem.StructureItem( + structures.firstOrNull { + component == it.componentName && preferredPanel?.name == it.structure + } ?: structures[0] + ) } } private fun updatePreferences(selectedItem: SelectedItem) { selectedComponentRepository.setSelectedComponent( - SelectedComponentRepository.SelectedComponent(selectedItem) + SelectedComponentRepository.SelectedComponent(selectedItem) ) } private fun maybeUpdateSelectedItem(item: SelectionItem): Boolean { - val newSelection = if (item.isPanel) { - SelectedItem.PanelItem(item.appName, item.componentName) - } else { - SelectedItem.StructureItem(allStructures.firstOrNull { - it.structure == item.structure && it.componentName == item.componentName - } ?: EMPTY_STRUCTURE) - } - return if (newSelection != selectedItem ) { + val newSelection = + if (item.isPanel) { + SelectedItem.PanelItem(item.appName, item.componentName) + } else { + SelectedItem.StructureItem( + allStructures.firstOrNull { + it.structure == item.structure && it.componentName == item.componentName + } ?: EMPTY_STRUCTURE + ) + } + return if (newSelection != selectedItem) { selectedItem = newSelection updatePreferences(selectedItem) true @@ -758,9 +816,7 @@ class ControlsUiControllerImpl @Inject constructor ( } popup = null - controlViewsById.forEach { - it.value.dismiss() - } + controlViewsById.forEach { it.value.dismiss() } controlActionCoordinator.closeDialogs() removeAppDialog?.cancel() } @@ -798,18 +854,14 @@ class ControlsUiControllerImpl @Inject constructor ( val key = ControlKey(componentName, c.getControlId()) controlsById.put(key, cws) - controlViewsById.get(key)?.let { - uiExecutor.execute { it.bindData(cws, isLocked) } - } + controlViewsById.get(key)?.let { uiExecutor.execute { it.bindData(cws, isLocked) } } } } } override fun onActionResponse(componentName: ComponentName, controlId: String, response: Int) { val key = ControlKey(componentName, controlId) - uiExecutor.execute { - controlViewsById.get(key)?.actionResponse(response) - } + uiExecutor.execute { controlViewsById.get(key)?.actionResponse(response) } } override fun onSizeChange() { @@ -830,16 +882,19 @@ class ControlsUiControllerImpl @Inject constructor ( private fun findSelectionItem(si: SelectedItem, items: List<SelectionItem>): SelectionItem? = items.firstOrNull { it.matches(si) } - override fun dump(pw: PrintWriter, args: Array<out String>) = pw.asIndenting().run { - println("ControlsUiControllerImpl:") - withIncreasedIndent { - println("hidden: $hidden") - println("selectedItem: $selectedItem") - println("lastSelections: $lastSelections") - println("setting: ${controlsSettingsRepository - .allowActionOnTrivialControlsInLockscreen.value}") + override fun dump(pw: PrintWriter, args: Array<out String>) = + pw.asIndenting().run { + println("ControlsUiControllerImpl:") + withIncreasedIndent { + println("hidden: $hidden") + println("selectedItem: $selectedItem") + println("lastSelections: $lastSelections") + println( + "setting: ${controlsSettingsRepository + .allowActionOnTrivialControlsInLockscreen.value}" + ) + } } - } } @VisibleForTesting @@ -849,9 +904,14 @@ internal data class SelectionItem( val icon: Drawable, val componentName: ComponentName, val uid: Int, - val panelComponentName: ComponentName? + val panelComponentName: ComponentName?, ) { - fun getTitle() = if (structure.isEmpty()) { appName } else { structure } + fun getTitle() = + if (structure.isEmpty()) { + appName + } else { + structure + } val isPanel: Boolean = panelComponentName != null @@ -872,7 +932,7 @@ internal data class SelectionItem( } private class ItemAdapter(parentContext: Context, val resource: Int) : - ArrayAdapter<SelectionItem>(parentContext, resource) { + ArrayAdapter<SelectionItem>(parentContext, resource) { private val layoutInflater = LayoutInflater.from(context)!! diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt index 41907882a443..e640be94073e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt @@ -20,21 +20,21 @@ import android.graphics.BlendMode import android.graphics.BlendModeColorFilter import android.graphics.drawable.ClipDrawable import android.graphics.drawable.LayerDrawable -import android.view.View import android.service.controls.Control import android.service.controls.templates.TemperatureControlTemplate import android.service.controls.templates.ThumbnailTemplate import android.util.TypedValue - -import com.android.systemui.res.R +import android.view.View import com.android.systemui.controls.ui.ControlViewHolder.Companion.MAX_LEVEL import com.android.systemui.controls.ui.ControlViewHolder.Companion.MIN_LEVEL +import com.android.systemui.res.R +import com.android.systemui.utils.SafeIconLoader /** * Supports display of static images on the background of the tile. When marked active, the title * and subtitle will not be visible. To be used with {@link Thumbnailtemplate} only. */ -class ThumbnailBehavior(currentUserId: Int) : Behavior { +class ThumbnailBehavior(currentUserId: Int, private val safeIconLoader: SafeIconLoader) : Behavior { lateinit var template: ThumbnailTemplate lateinit var control: Control lateinit var cvh: ControlViewHolder @@ -61,17 +61,20 @@ class ThumbnailBehavior(currentUserId: Int) : Behavior { shadowRadius = outValue.getFloat() shadowColor = cvh.context.resources.getColor(R.color.control_thumbnail_shadow_color) - cvh.layout.setOnClickListener(View.OnClickListener() { - cvh.controlActionCoordinator.touch(cvh, template.getTemplateId(), control) - }) + cvh.layout.setOnClickListener( + View.OnClickListener() { + cvh.controlActionCoordinator.touch(cvh, template.getTemplateId(), control) + } + ) } override fun bind(cws: ControlWithState, colorOffset: Int) { this.control = cws.control!! cvh.setStatusText(control.getStatusText()) - template = control.controlTemplate as? ThumbnailTemplate + template = + control.controlTemplate as? ThumbnailTemplate ?: (control.controlTemplate as TemperatureControlTemplate).template - as ThumbnailTemplate + as ThumbnailTemplate val ld = cvh.layout.getBackground() as LayerDrawable val clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable @@ -84,18 +87,22 @@ class ThumbnailBehavior(currentUserId: Int) : Behavior { cvh.status.setShadowLayer(shadowOffsetX, shadowOffsetY, shadowRadius, shadowColor) cvh.bgExecutor.execute { - val drawable = template.thumbnail - ?.takeIf(canUseIconPredicate) - ?.loadDrawable(cvh.context) + val drawable = + template.thumbnail.takeIf(canUseIconPredicate)?.let { safeIconLoader.load(it) } cvh.uiExecutor.execute { - val radius = cvh.context.getResources() - .getDimensionPixelSize(R.dimen.control_corner_radius).toFloat() + val radius = + cvh.context + .getResources() + .getDimensionPixelSize(R.dimen.control_corner_radius) + .toFloat() // TODO(b/290037843): Add a placeholder - drawable?.let { - clipLayer.drawable = CornerDrawable(it, radius) - } - clipLayer.setColorFilter(BlendModeColorFilter(cvh.context.resources - .getColor(R.color.control_thumbnail_tint), BlendMode.LUMINOSITY)) + drawable?.let { clipLayer.drawable = CornerDrawable(it, radius) } + clipLayer.setColorFilter( + BlendModeColorFilter( + cvh.context.resources.getColor(R.color.control_thumbnail_tint), + BlendMode.LUMINOSITY, + ) + ) cvh.applyRenderInfo(enabled, colorOffset) } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java index 1125d2ccdd97..8e0beda9eff7 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java @@ -72,6 +72,7 @@ import android.hardware.display.DisplayManager; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.input.InputManager; +import android.hardware.location.ContextHubManager; import android.location.LocationManager; import android.media.AudioManager; import android.media.IAudioService; @@ -238,6 +239,13 @@ public class FrameworkServicesModule { @Provides @Singleton + @Nullable + static ContextHubManager provideContextHubManager(Context context) { + return context.getSystemService(ContextHubManager.class); + } + + @Provides + @Singleton static DevicePolicyManager provideDevicePolicyManager(Context context) { return context.getSystemService(DevicePolicyManager.class); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index 3050cba12f09..3c68e3a09f02 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -30,6 +30,7 @@ import com.android.systemui.accessibility.SystemActionsModule; import com.android.systemui.accessibility.data.repository.AccessibilityRepositoryModule; import com.android.systemui.battery.BatterySaverModule; import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayOverrideModule; +import com.android.systemui.communal.posturing.dagger.NoopPosturingModule; import com.android.systemui.display.ui.viewmodel.ConnectingDisplayViewModel; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; @@ -74,9 +75,9 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.dagger.CentralSurfacesModule; import com.android.systemui.statusbar.dagger.StartCentralSurfacesModule; import com.android.systemui.statusbar.notification.dagger.ReferenceNotificationsModule; +import com.android.systemui.statusbar.notification.headsup.HeadsUpModule; import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.DozeServiceHost; -import com.android.systemui.statusbar.notification.headsup.HeadsUpModule; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule; import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentStartableModule; @@ -149,6 +150,7 @@ import javax.inject.Named; RearDisplayModule.class, RecentsModule.class, ReferenceNotificationsModule.class, + NoopPosturingModule.class, ReferenceScreenshotModule.class, RotationLockModule.class, RotationLockNewModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt b/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt index 62ab18bbb738..96ef03c996a9 100644 --- a/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt +++ b/packages/SystemUI/src/com/android/systemui/grid/ui/compose/SpannedGrids.kt @@ -20,6 +20,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope import androidx.compose.runtime.Composable +import androidx.compose.runtime.key import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout @@ -63,6 +64,7 @@ fun HorizontalSpannedGrid( rowSpacing: Dp, spans: List<Int>, modifier: Modifier = Modifier, + keys: (spanIndex: Int) -> Any = { it }, composables: @Composable BoxScope.(spanIndex: Int) -> Unit, ) { SpannedGrid( @@ -72,6 +74,7 @@ fun HorizontalSpannedGrid( spans = spans, isVertical = false, modifier = modifier, + keys = keys, composables = composables, ) } @@ -103,6 +106,7 @@ fun VerticalSpannedGrid( rowSpacing: Dp, spans: List<Int>, modifier: Modifier = Modifier, + keys: (spanIndex: Int) -> Any = { it }, composables: @Composable BoxScope.(spanIndex: Int) -> Unit, ) { SpannedGrid( @@ -112,6 +116,7 @@ fun VerticalSpannedGrid( spans = spans, isVertical = true, modifier = modifier, + keys = keys, composables = composables, ) } @@ -124,6 +129,7 @@ private fun SpannedGrid( spans: List<Int>, isVertical: Boolean, modifier: Modifier = Modifier, + keys: (spanIndex: Int) -> Any = { it }, composables: @Composable BoxScope.(spanIndex: Int) -> Unit, ) { val crossAxisArrangement = Arrangement.spacedBy(crossAxisSpacing) @@ -167,17 +173,19 @@ private fun SpannedGrid( Layout( { (0 until spans.size).map { spanIndex -> - Box( - Modifier.semantics { - collectionItemInfo = - if (isVertical) { - CollectionItemInfo(spanIndex, 1, 0, 1) - } else { - CollectionItemInfo(0, 1, spanIndex, 1) - } + key(keys(spanIndex)) { + Box( + Modifier.semantics { + collectionItemInfo = + if (isVertical) { + CollectionItemInfo(spanIndex, 1, 0, 1) + } else { + CollectionItemInfo(0, 1, spanIndex, 1) + } + } + ) { + composables(spanIndex) } - ) { - composables(spanIndex) } } }, diff --git a/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt b/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt index 84c4bdf1621a..49625f8f9360 100644 --- a/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt @@ -17,6 +17,7 @@ package com.android.systemui.haptics.msdl.qs import android.service.quicksettings.Tile +import androidx.compose.runtime.Stable import com.android.systemui.Flags import com.android.systemui.animation.Expandable import com.android.systemui.dagger.SysUISingleton @@ -175,6 +176,7 @@ constructor( } @SysUISingleton +@Stable class TileHapticsViewModelFactoryProvider @Inject constructor(private val tileHapticsViewModelFactory: TileHapticsViewModel.Factory) { diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt index d8532c176619..ee10c9edaa39 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt @@ -21,12 +21,14 @@ import com.android.systemui.Flags.keyboardShortcutHelperRewrite import com.android.systemui.keyboard.shortcut.data.repository.CustomShortcutCategoriesRepository import com.android.systemui.keyboard.shortcut.data.repository.DefaultShortcutCategoriesRepository import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesRepository +import com.android.systemui.keyboard.shortcut.data.source.AccessibilityShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.AppCategoriesShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.CurrentAppShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.InputShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.KeyboardShortcutGroupsSource import com.android.systemui.keyboard.shortcut.data.source.MultitaskingShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.SystemShortcutsSource +import com.android.systemui.keyboard.shortcut.qualifiers.AccessibilityShortcuts import com.android.systemui.keyboard.shortcut.qualifiers.AppCategoriesShortcuts import com.android.systemui.keyboard.shortcut.qualifiers.CurrentAppShortcuts import com.android.systemui.keyboard.shortcut.qualifiers.CustomShortcutCategories @@ -68,6 +70,12 @@ interface ShortcutHelperModule { ): KeyboardShortcutGroupsSource @Binds + @AccessibilityShortcuts + fun accessibilityShortcutsSource( + impl: AccessibilityShortcutsSource + ): KeyboardShortcutGroupsSource + + @Binds @DefaultShortcutCategories fun defaultShortcutCategoriesRepository( impl: DefaultShortcutCategoriesRepository diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/DefaultShortcutCategoriesRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/DefaultShortcutCategoriesRepository.kt index db35d49e7598..c36b8af1a669 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/DefaultShortcutCategoriesRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/DefaultShortcutCategoriesRepository.kt @@ -23,6 +23,7 @@ import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutGroup import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutInfo import com.android.systemui.keyboard.shortcut.data.source.KeyboardShortcutGroupsSource +import com.android.systemui.keyboard.shortcut.qualifiers.AccessibilityShortcuts import com.android.systemui.keyboard.shortcut.qualifiers.AppCategoriesShortcuts import com.android.systemui.keyboard.shortcut.qualifiers.CurrentAppShortcuts import com.android.systemui.keyboard.shortcut.qualifiers.InputShortcuts @@ -30,6 +31,7 @@ import com.android.systemui.keyboard.shortcut.qualifiers.MultitaskingShortcuts import com.android.systemui.keyboard.shortcut.qualifiers.SystemShortcuts import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.Accessibility import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.AppCategories import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.CurrentApp import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.InputMethodEditor @@ -47,11 +49,12 @@ class DefaultShortcutCategoriesRepository @Inject constructor( @Background private val backgroundScope: CoroutineScope, - @SystemShortcuts private val systemShortcutsSource: KeyboardShortcutGroupsSource, - @MultitaskingShortcuts private val multitaskingShortcutsSource: KeyboardShortcutGroupsSource, - @AppCategoriesShortcuts private val appCategoriesShortcutsSource: KeyboardShortcutGroupsSource, - @InputShortcuts private val inputShortcutsSource: KeyboardShortcutGroupsSource, - @CurrentAppShortcuts private val currentAppShortcutsSource: KeyboardShortcutGroupsSource, + @SystemShortcuts systemShortcutsSource: KeyboardShortcutGroupsSource, + @MultitaskingShortcuts multitaskingShortcutsSource: KeyboardShortcutGroupsSource, + @AppCategoriesShortcuts appCategoriesShortcutsSource: KeyboardShortcutGroupsSource, + @InputShortcuts inputShortcutsSource: KeyboardShortcutGroupsSource, + @CurrentAppShortcuts currentAppShortcutsSource: KeyboardShortcutGroupsSource, + @AccessibilityShortcuts accessibilityShortcutsSource: KeyboardShortcutGroupsSource, inputDeviceRepository: ShortcutHelperInputDeviceRepository, shortcutCategoriesUtils: ShortcutCategoriesUtils, ) : ShortcutCategoriesRepository { @@ -72,6 +75,10 @@ constructor( typeProvider = { InputMethodEditor }, ), InternalGroupsSource( + source = accessibilityShortcutsSource, + typeProvider = { Accessibility }, + ), + InternalGroupsSource( source = currentAppShortcutsSource, typeProvider = { groups -> getCurrentAppShortcutCategoryType(groups) }, ), diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/AccessibilityShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/AccessibilityShortcutsSource.kt new file mode 100644 index 000000000000..d92c45591522 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/AccessibilityShortcutsSource.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.data.source + +import android.content.res.Resources +import android.view.KeyboardShortcutGroup +import android.view.KeyboardShortcutInfo +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.res.R +import javax.inject.Inject + +class AccessibilityShortcutsSource @Inject constructor(@Main private val resources: Resources) : + KeyboardShortcutGroupsSource { + override suspend fun shortcutGroups(deviceId: Int): List<KeyboardShortcutGroup> = + listOf( + KeyboardShortcutGroup( + /* label= */ resources.getString(R.string.shortcutHelper_category_accessibility), + accessibilityShortcuts(), + ) + ) + + private fun accessibilityShortcuts() = listOf<KeyboardShortcutInfo>() +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/AccessibilityShortcuts.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/AccessibilityShortcuts.kt new file mode 100644 index 000000000000..2f939145734b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/AccessibilityShortcuts.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.qualifiers + +import javax.inject.Qualifier + +@Qualifier annotation class AccessibilityShortcuts diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt index 464805334c2a..110ea34e9b0e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt @@ -40,6 +40,11 @@ sealed interface ShortcutCategoryType { override val includeInCustomization: Boolean = true } + data object Accessibility : ShortcutCategoryType { + override val isTrusted: Boolean = false + override val includeInCustomization: Boolean = true + } + data class CurrentApp(val packageName: String) : ShortcutCategoryType { override val isTrusted: Boolean = false override val includeInCustomization: Boolean = false diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt index d8e2dabde8a9..550438aa220f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt @@ -107,16 +107,13 @@ private fun AddShortcutDialog( onCancel: () -> Unit, onConfirmSetShortcut: () -> Unit, ) { - Column(modifier = modifier) { + Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) { Title(uiState.shortcutLabel) Description( text = stringResource(id = R.string.shortcut_customize_mode_add_shortcut_description) ) PromptShortcutModifier( - modifier = - Modifier.padding(top = 24.dp, start = 116.5.dp, end = 116.5.dp) - .width(131.dp) - .height(48.dp), + modifier = Modifier.padding(top = 24.dp).sizeIn(minWidth = 131.dp, minHeight = 48.dp), defaultModifierKey = uiState.defaultCustomShortcutModifierKey, ) SelectedKeyCombinationContainer( @@ -216,14 +213,14 @@ private fun DialogButtons( modifier = Modifier.heightIn(40.dp), contentColor = MaterialTheme.colorScheme.primary, text = stringResource(R.string.shortcut_helper_customize_dialog_cancel_button_label), - border = BorderStroke(width = 1.dp, color = MaterialTheme.colorScheme.outlineVariant) + border = BorderStroke(width = 1.dp, color = MaterialTheme.colorScheme.outlineVariant), ) Spacer(modifier = Modifier.width(8.dp)) ShortcutHelperButton( - modifier = Modifier - .heightIn(40.dp) - .focusRequester(focusRequester) - .focusProperties { canFocus = true }, // enable focus on touch/click mode + modifier = + Modifier.heightIn(40.dp).focusRequester(focusRequester).focusProperties { + canFocus = true + }, // enable focus on touch/click mode onClick = onConfirm, color = MaterialTheme.colorScheme.primary, contentColor = MaterialTheme.colorScheme.onPrimary, @@ -236,7 +233,10 @@ private fun DialogButtons( @Composable private fun ErrorMessageContainer(errorMessage: String) { if (errorMessage.isNotEmpty()) { - Box(modifier = Modifier.padding(horizontal = 16.dp).width(332.dp).height(40.dp)) { + Box( + modifier = + Modifier.padding(horizontal = 16.dp).sizeIn(minWidth = 332.dp, minHeight = 40.dp) + ) { Text( text = errorMessage, style = MaterialTheme.typography.bodyMedium, @@ -405,7 +405,11 @@ private fun PromptShortcutModifier( modifier: Modifier, defaultModifierKey: ShortcutKey.Icon.ResIdIcon, ) { - Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(2.dp)) { + Row( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(2.dp), + verticalAlignment = Alignment.CenterVertically, + ) { ActionKeyContainer(defaultModifierKey) PlusIconContainer() } @@ -422,6 +426,7 @@ private fun ActionKeyContainer(defaultModifierKey: ShortcutKey.Icon.ResIdIcon) { ) .padding(all = 12.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically, ) { ActionKeyIcon(defaultModifierKey) ActionKeyText() diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt index d61165c16625..f11205fd7246 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt @@ -21,6 +21,8 @@ import android.content.Context import android.content.pm.PackageManager.NameNotFoundException import android.util.Log import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Accessibility +import androidx.compose.material.icons.filled.AccessibilityNew import androidx.compose.material.icons.filled.Android import androidx.compose.material.icons.filled.Apps import androidx.compose.material.icons.filled.Keyboard @@ -41,6 +43,7 @@ import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCategoryUi import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState import com.android.systemui.res.R import com.android.systemui.settings.UserTracker +import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow @@ -51,7 +54,6 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext -import javax.inject.Inject class ShortcutHelperViewModel @Inject @@ -89,8 +91,9 @@ constructor( searchQuery = query, shortcutCategories = shortcutCategoriesUi, defaultSelectedCategory = getDefaultSelectedCategory(filteredCategories), - isShortcutCustomizerFlagEnabled = keyboardShortcutHelperShortcutCustomizer(), - shouldShowResetButton = shouldShowResetButton(shortcutCategoriesUi) + isShortcutCustomizerFlagEnabled = + keyboardShortcutHelperShortcutCustomizer(), + shouldShowResetButton = shouldShowResetButton(shortcutCategoriesUi), ) } } @@ -137,6 +140,9 @@ constructor( IconSource(imageVector = Icons.Default.Android) } } + + ShortcutCategoryType.Accessibility -> + IconSource(imageVector = Icons.Default.AccessibilityNew) } } @@ -151,6 +157,8 @@ constructor( ShortcutCategoryType.AppCategories -> context.getString(R.string.shortcut_helper_category_app_shortcuts) is CurrentApp -> getApplicationLabelForCurrentApp(type) + ShortcutCategoryType.Accessibility -> + context.getString(R.string.shortcutHelper_category_accessibility) } private fun getApplicationLabelForCurrentApp(type: CurrentApp): String { @@ -245,7 +253,7 @@ constructor( searchQuery.value = query } - private fun resetSearchQuery(){ + private fun resetSearchQuery() { searchQuery.value = "" } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index 591383999182..1d36076347bf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -72,6 +72,7 @@ import com.android.internal.policy.IKeyguardDrawnCallback; import com.android.internal.policy.IKeyguardExitCallback; import com.android.internal.policy.IKeyguardService; import com.android.internal.policy.IKeyguardStateCallback; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.SystemUIApplication; import com.android.systemui.dagger.qualifiers.Application; @@ -331,6 +332,7 @@ public class KeyguardService extends Service { } }; private final KeyguardServiceLockNowInteractor mKeyguardServiceLockNowInteractor; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Inject public KeyguardService( @@ -356,7 +358,8 @@ public class KeyguardService extends Service { KeyguardDismissInteractor keyguardDismissInteractor, Lazy<DeviceEntryInteractor> deviceEntryInteractorLazy, KeyguardStateCallbackInteractor keyguardStateCallbackInteractor, - KeyguardServiceLockNowInteractor keyguardServiceLockNowInteractor) { + KeyguardServiceLockNowInteractor keyguardServiceLockNowInteractor, + KeyguardUpdateMonitor keyguardUpdateMonitor) { super(); mKeyguardViewMediator = keyguardViewMediator; mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher; @@ -389,6 +392,7 @@ public class KeyguardService extends Service { mKeyguardWakeDirectlyToGoneInteractor = keyguardWakeDirectlyToGoneInteractor; mKeyguardDismissInteractor = keyguardDismissInteractor; mKeyguardServiceLockNowInteractor = keyguardServiceLockNowInteractor; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; } @Override @@ -585,6 +589,7 @@ public class KeyguardService extends Service { mPowerInteractor.onScreenPowerStateUpdated(ScreenPowerState.SCREEN_TURNING_ON); mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNING_ON, callback); + mKeyguardUpdateMonitor.triggerTimeUpdate(); final String onDrawWaitingTraceTag = "Waiting for KeyguardDrawnCallback#onDrawn"; final int traceCookie = System.identityHashCode(callback); @@ -620,6 +625,7 @@ public class KeyguardService extends Service { checkPermission(); mPowerInteractor.onScreenPowerStateUpdated(ScreenPowerState.SCREEN_ON); mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNED_ON); + mKeyguardUpdateMonitor.triggerTimeUpdate(); mScreenOnCoordinator.onScreenTurnedOn(); Trace.endSection(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt index a45204d41718..80675d373b8e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt @@ -28,7 +28,6 @@ object BuiltInKeyguardQuickAffordanceKeys { const val CREATE_NOTE = "create_note" const val DO_NOT_DISTURB = "do_not_disturb" const val FLASHLIGHT = "flashlight" - const val GLANCEABLE_HUB = "glanceable_hub" const val HOME_CONTROLS = "home" const val MUTE = "mute" const val QR_CODE_SCANNER = "qr_code_scanner" diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt deleted file mode 100644 index 96b07cc84705..000000000000 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.keyguard.data.quickaffordance - -import android.content.Context -import android.content.Intent -import android.provider.Settings -import android.util.Log -import com.android.systemui.animation.Expandable -import com.android.systemui.common.shared.model.ContentDescription -import com.android.systemui.common.shared.model.Icon -import com.android.systemui.communal.data.repository.CommunalSceneRepository -import com.android.systemui.communal.domain.interactor.CommunalInteractor -import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor -import com.android.systemui.communal.shared.model.CommunalScenes -import com.android.systemui.communal.shared.model.CommunalTransitionKeys -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.res.R -import com.android.systemui.scene.domain.interactor.SceneInteractor -import com.android.systemui.scene.shared.flag.SceneContainerFlag -import com.android.systemui.scene.shared.model.Scenes -import javax.inject.Inject -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map - -/** Lockscreen affordance that opens the glanceable hub. */ -@SysUISingleton -class GlanceableHubQuickAffordanceConfig -@Inject -constructor( - @Application private val context: Context, - private val communalSceneRepository: CommunalSceneRepository, - private val communalInteractor: CommunalInteractor, - private val communalSettingsInteractor: CommunalSettingsInteractor, - private val sceneInteractor: SceneInteractor, -) : KeyguardQuickAffordanceConfig { - - private val pickerNameResourceId = R.string.glanceable_hub_lockscreen_affordance_label - - override val key: String = BuiltInKeyguardQuickAffordanceKeys.GLANCEABLE_HUB - - override fun pickerName(): String = context.getString(pickerNameResourceId) - - override val pickerIconResourceId: Int - get() = R.drawable.ic_widgets - - override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> - get() = - communalInteractor.isCommunalAvailable.map { available -> - if (!communalSettingsInteractor.isV2FlagEnabled()) { - Log.i(TAG, "Button hidden on lockscreen: flag not enabled.") - KeyguardQuickAffordanceConfig.LockScreenState.Hidden - } else if (!available) { - Log.i(TAG, "Button hidden on lockscreen: hub not available.") - KeyguardQuickAffordanceConfig.LockScreenState.Hidden - } else { - KeyguardQuickAffordanceConfig.LockScreenState.Visible( - icon = - Icon.Resource( - pickerIconResourceId, - ContentDescription.Resource(pickerNameResourceId), - ) - ) - } - } - - override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState { - return if (!communalSettingsInteractor.isV2FlagEnabled()) { - Log.i(TAG, "Button unavailable in picker: flag not enabled.") - KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice - } else if (!communalInteractor.isCommunalEnabled.value) { - Log.i(TAG, "Button disabled in picker: hub not enabled in settings.") - KeyguardQuickAffordanceConfig.PickerScreenState.Disabled( - explanation = - context.getString(R.string.glanceable_hub_lockscreen_affordance_disabled_text), - actionText = - context.getString( - R.string.glanceable_hub_lockscreen_affordance_action_button_label - ), - actionIntent = Intent(Settings.ACTION_LOCKSCREEN_SETTINGS), - ) - } else { - KeyguardQuickAffordanceConfig.PickerScreenState.Default() - } - } - - override fun onTriggered( - expandable: Expandable? - ): KeyguardQuickAffordanceConfig.OnTriggeredResult { - if (SceneContainerFlag.isEnabled) { - sceneInteractor.changeScene(Scenes.Communal, "lockscreen to communal from shortcut") - } else { - communalSceneRepository.changeScene( - CommunalScenes.Communal, - transitionKey = CommunalTransitionKeys.SimpleFade, - ) - } - return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled(true) - } - - companion object { - private const val TAG = "GlanceableHubQuickAffordanceConfig" - } -} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt index 8c6fdb989daf..787a9837b860 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt @@ -36,7 +36,6 @@ interface KeyguardDataQuickAffordanceModule { camera: CameraQuickAffordanceConfig, doNotDisturb: DoNotDisturbQuickAffordanceConfig, flashlight: FlashlightQuickAffordanceConfig, - glanceableHub: GlanceableHubQuickAffordanceConfig, home: HomeControlsKeyguardQuickAffordanceConfig, mute: MuteQuickAffordanceConfig, quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig, @@ -47,7 +46,6 @@ interface KeyguardDataQuickAffordanceModule { camera, doNotDisturb, flashlight, - glanceableHub, home, mute, quickAccessWallet, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt index b42da5265d86..717437923e57 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt @@ -36,6 +36,7 @@ import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce @SysUISingleton @@ -80,6 +81,7 @@ constructor( /** * Listen for the signal that we're waking up and figure what state we need to transition to. */ + @OptIn(FlowPreview::class) private fun listenForAodToAwake() { // Use PowerInteractor's wakefulness, which is the earliest wake signal available. We // have all of the information we need at this time to make a decision about where to diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt index 021cce6d1e23..4291181d8336 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt @@ -41,6 +41,7 @@ import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce @SysUISingleton @@ -114,6 +115,7 @@ constructor( } } + @OptIn(FlowPreview::class) @SuppressLint("MissingPermission") private fun listenForDozingToAny() { if (KeyguardWmStateRefactor.isEnabled) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt index a9992112f893..82b8ca2a890b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt @@ -125,6 +125,7 @@ constructor( * the power button is pressed quickly, we may need to go directly from DREAMING to * GLANCEABLE_HUB as the transition to DOZING has not occurred yet. */ + @OptIn(FlowPreview::class) @SuppressLint("MissingPermission") private fun listenForDreamingToGlanceableHubFromPowerButton() { if (!communalSettingsInteractor.isCommunalFlagEnabled()) return diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index 8f7f2a0a8cbb..1f3c08ca9f7a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -56,6 +56,7 @@ import javax.inject.Inject import javax.inject.Provider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -203,6 +204,7 @@ constructor( * examining the value of this flow, to let other consumers have enough time to also see that * same new value. */ + @OptIn(FlowPreview::class) val isAbleToDream: Flow<Boolean> = dozeTransitionModel .flatMapLatest { dozeTransitionModel -> diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt index cd62d5f3b6e1..3dc123a81bde 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt @@ -30,6 +30,7 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce private val TAG = KeyguardTransitionAuditLogger::class.simpleName!! @@ -52,6 +53,7 @@ constructor( private val deviceEntryInteractor: DeviceEntryInteractor, ) { + @OptIn(FlowPreview::class) fun start() { scope.launch { powerInteractor.detailedWakefulness.collect { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt index f34cc07f26ae..82abb05177e1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt @@ -23,6 +23,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.view.layout.sections.AccessibilityActionsSection import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection +import com.android.systemui.keyguard.ui.view.layout.sections.AodPromotedNotificationSection import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection @@ -60,6 +61,7 @@ constructor( defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection, defaultStatusBarSection: DefaultStatusBarSection, defaultNotificationStackScrollLayoutSection: DefaultNotificationStackScrollLayoutSection, + aodPromotedNotificationSection: AodPromotedNotificationSection, aodNotificationIconsSection: AodNotificationIconsSection, aodBurnInSection: AodBurnInSection, clockSection: ClockSection, @@ -79,6 +81,7 @@ constructor( defaultStatusBarSection, defaultNotificationStackScrollLayoutSection, aodNotificationIconsSection, + aodPromotedNotificationSection, smartspaceSection, aodBurnInSection, clockSection, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt index 6f7872c9cb96..4f4442350873 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt @@ -38,6 +38,7 @@ import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDi import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder import com.android.systemui.statusbar.notification.icon.ui.viewbinder.StatusBarIconViewBindingFailureTracker import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel +import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiAod import com.android.systemui.statusbar.phone.NotificationIconContainer import com.android.systemui.statusbar.ui.SystemBarUtilsState import com.android.systemui.util.ui.value @@ -94,7 +95,11 @@ constructor( context.resources.getDimensionPixelSize(R.dimen.keyguard_status_view_bottom_margin) val isVisible = rootViewModel.isNotifIconContainerVisible.value constraintSet.apply { - connect(nicId, TOP, R.id.smart_space_barrier_bottom, BOTTOM, bottomMargin) + if (PromotedNotificationUiAod.isEnabled) { + connect(nicId, TOP, AodPromotedNotificationSection.viewId, BOTTOM, bottomMargin) + } else { + connect(nicId, TOP, R.id.smart_space_barrier_bottom, BOTTOM, bottomMargin) + } setGoneMargin(nicId, BOTTOM, bottomMargin) setVisibility(nicId, if (isVisible.value) VISIBLE else GONE) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodPromotedNotificationSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodPromotedNotificationSection.kt new file mode 100644 index 000000000000..ed1bdb0e2922 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodPromotedNotificationSection.kt @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.view.layout.sections + +import androidx.compose.ui.platform.ComposeView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.constraintlayout.widget.ConstraintSet +import androidx.constraintlayout.widget.ConstraintSet.BOTTOM +import androidx.constraintlayout.widget.ConstraintSet.END +import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID +import androidx.constraintlayout.widget.ConstraintSet.START +import androidx.constraintlayout.widget.ConstraintSet.TOP +import com.android.systemui.keyguard.shared.model.KeyguardSection +import com.android.systemui.res.R +import com.android.systemui.statusbar.notification.promoted.AODPromotedNotification +import com.android.systemui.statusbar.notification.promoted.PromotedNotificationLogger +import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiAod +import com.android.systemui.statusbar.notification.promoted.ui.viewmodel.AODPromotedNotificationViewModel +import javax.inject.Inject + +class AodPromotedNotificationSection +@Inject +constructor( + private val viewModelFactory: AODPromotedNotificationViewModel.Factory, + private val logger: PromotedNotificationLogger, +) : KeyguardSection() { + var view: ComposeView? = null + + override fun addViews(constraintLayout: ConstraintLayout) { + if (!PromotedNotificationUiAod.isEnabled) { + return + } + + check(view == null) + + view = + ComposeView(constraintLayout.context).apply { + setContent { AODPromotedNotification(viewModelFactory) } + id = viewId + constraintLayout.addView(this) + } + + logger.logSectionAddedViews() + } + + override fun bindData(constraintLayout: ConstraintLayout) { + if (!PromotedNotificationUiAod.isEnabled) { + return + } + + checkNotNull(view) + + // Do nothing; the binding happens in the AODPromotedNotification Composable. + + logger.logSectionBoundData() + } + + override fun applyConstraints(constraintSet: ConstraintSet) { + if (!PromotedNotificationUiAod.isEnabled) { + return + } + + checkNotNull(view) + + constraintSet.apply { + connect(viewId, TOP, R.id.smart_space_barrier_bottom, BOTTOM, 0) + connect(viewId, START, PARENT_ID, START, 0) + connect(viewId, END, PARENT_ID, END, 0) + + constrainWidth(viewId, ConstraintSet.MATCH_CONSTRAINT) + constrainHeight(viewId, ConstraintSet.WRAP_CONTENT) + } + + logger.logSectionAppliedConstraints() + } + + override fun removeViews(constraintLayout: ConstraintLayout) { + if (!PromotedNotificationUiAod.isEnabled) { + return + } + + constraintLayout.removeView(checkNotNull(view)) + + view = null + + logger.logSectionRemovedViews() + } + + companion object { + val viewId = R.id.aod_promoted_notification_frame + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt index a595d815e016..29bda7623675 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt @@ -86,15 +86,56 @@ class ClockSizeTransition( transition.values[SMARTSPACE_BOUNDS] = targetSSView.getRect() } - open fun mutateBounds( - view: View, - fromIsVis: Boolean, - toIsVis: Boolean, - fromBounds: Rect, - toBounds: Rect, - fromSSBounds: Rect?, - toSSBounds: Rect?, - ) {} + open fun initTargets(from: Target, to: Target) {} + + open fun mutateTargets(from: Target, to: Target) {} + + data class Target( + var view: View, + var visibility: Int, + var isVisible: Boolean, + var alpha: Float, + var bounds: Rect, + var ssBounds: Rect?, + ) { + companion object { + fun fromStart(startValues: TransitionValues): Target { + var fromVis = startValues.values[PROP_VISIBILITY] as Int + var fromIsVis = fromVis == View.VISIBLE + var fromAlpha = startValues.values[PROP_ALPHA] as Float + + // Align starting visibility and alpha + if (!fromIsVis) fromAlpha = 0f + else if (fromAlpha <= 0f) { + fromIsVis = false + fromVis = View.INVISIBLE + } + + return Target( + view = startValues.view, + visibility = fromVis, + isVisible = fromIsVis, + alpha = fromAlpha, + bounds = startValues.values[PROP_BOUNDS] as Rect, + ssBounds = startValues.values[SMARTSPACE_BOUNDS] as Rect?, + ) + } + + fun fromEnd(endValues: TransitionValues): Target { + val toVis = endValues.values[PROP_VISIBILITY] as Int + val toIsVis = toVis == View.VISIBLE + + return Target( + view = endValues.view, + visibility = toVis, + isVisible = toIsVis, + alpha = if (toIsVis) 1f else 0f, + bounds = endValues.values[PROP_BOUNDS] as Rect, + ssBounds = endValues.values[SMARTSPACE_BOUNDS] as Rect?, + ) + } + } + } override fun createAnimator( sceenRoot: ViewGroup, @@ -109,72 +150,58 @@ class ClockSizeTransition( return null } - var fromVis = startValues.values[PROP_VISIBILITY] as Int - var fromIsVis = fromVis == View.VISIBLE - var fromAlpha = startValues.values[PROP_ALPHA] as Float - val fromBounds = startValues.values[PROP_BOUNDS] as Rect - val fromSSBounds = startValues.values[SMARTSPACE_BOUNDS] as Rect? - - val toView = endValues.view - val toVis = endValues.values[PROP_VISIBILITY] as Int - val toBounds = endValues.values[PROP_BOUNDS] as Rect - val toSSBounds = endValues.values[SMARTSPACE_BOUNDS] as Rect? - val toIsVis = toVis == View.VISIBLE - val toAlpha = if (toIsVis) 1f else 0f - - // Align starting visibility and alpha - if (!fromIsVis) fromAlpha = 0f - else if (fromAlpha <= 0f) { - fromIsVis = false - fromVis = View.INVISIBLE - } + val from = Target.fromStart(startValues) + val to = Target.fromEnd(endValues) + initTargets(from, to) + mutateTargets(from, to) - mutateBounds(toView, fromIsVis, toIsVis, fromBounds, toBounds, fromSSBounds, toSSBounds) - if (fromIsVis == toIsVis && fromBounds.equals(toBounds)) { + if (from.isVisible == to.isVisible && from.bounds.equals(to.bounds)) { if (DEBUG) { Log.w( TAG, - "Skipping no-op transition: $toView; " + - "vis: $fromVis -> $toVis; " + - "alpha: $fromAlpha -> $toAlpha; " + - "bounds: $fromBounds -> $toBounds; ", + "Skipping no-op transition: ${to.view}; " + + "vis: ${from.visibility} -> ${to.visibility}; " + + "alpha: ${from.alpha} -> ${to.alpha}; " + + "bounds: ${from.bounds} -> ${to.bounds}; ", ) } return null } - val sendToBack = fromIsVis && !toIsVis + val sendToBack = from.isVisible && !to.isVisible fun lerp(start: Int, end: Int, fract: Float): Int = MathUtils.lerp(start.toFloat(), end.toFloat(), fract).toInt() fun computeBounds(fract: Float): Rect = Rect( - lerp(fromBounds.left, toBounds.left, fract), - lerp(fromBounds.top, toBounds.top, fract), - lerp(fromBounds.right, toBounds.right, fract), - lerp(fromBounds.bottom, toBounds.bottom, fract), + lerp(from.bounds.left, to.bounds.left, fract), + lerp(from.bounds.top, to.bounds.top, fract), + lerp(from.bounds.right, to.bounds.right, fract), + lerp(from.bounds.bottom, to.bounds.bottom, fract), ) fun assignAnimValues(src: String, fract: Float, vis: Int? = null) { + mutateTargets(from, to) val bounds = computeBounds(fract) - val alpha = MathUtils.lerp(fromAlpha, toAlpha, fract) + val alpha = MathUtils.lerp(from.alpha, to.alpha, fract) if (DEBUG) { Log.i( TAG, - "$src: $toView; fract=$fract; alpha=$alpha; vis=$vis; bounds=$bounds;", + "$src: ${to.view}; fract=$fract; alpha=$alpha; vis=$vis; bounds=$bounds;", ) } - toView.setVisibility(vis ?: View.VISIBLE) - toView.setAlpha(alpha) - toView.setRect(bounds) + + to.view.setVisibility(vis ?: View.VISIBLE) + to.view.setAlpha(alpha) + to.view.setRect(bounds) } if (DEBUG) { Log.i( TAG, - "transitioning: $toView; " + - "vis: $fromVis -> $toVis; " + - "alpha: $fromAlpha -> $toAlpha; " + - "bounds: $fromBounds -> $toBounds; ", + "transitioning: ${to.view}; " + + "vis: ${from.visibility} -> ${to.visibility}; " + + "alpha: ${from.alpha} -> ${to.alpha}; " + + "bounds: ${from.bounds} -> ${to.bounds}; ", ) } @@ -190,11 +217,11 @@ class ClockSizeTransition( this@VisibilityBoundsTransition.addListener( object : TransitionListenerAdapter() { override fun onTransitionStart(t: Transition) { - toView.viewTreeObserver.addOnPreDrawListener(predrawCallback) + to.view.viewTreeObserver.addOnPreDrawListener(predrawCallback) } override fun onTransitionEnd(t: Transition) { - toView.viewTreeObserver.removeOnPreDrawListener(predrawCallback) + to.view.viewTreeObserver.removeOnPreDrawListener(predrawCallback) } } ) @@ -202,17 +229,17 @@ class ClockSizeTransition( val listener = object : AnimatorListenerAdapter() { override fun onAnimationStart(anim: Animator) { - assignAnimValues("start", 0f, fromVis) + assignAnimValues("start", 0f, from.visibility) } override fun onAnimationEnd(anim: Animator) { - assignAnimValues("end", 1f, toVis) - if (sendToBack) toView.translationZ = 0f + assignAnimValues("end", 1f, to.visibility) + if (sendToBack) to.view.translationZ = 0f } } anim.addListener(listener) - assignAnimValues("init", 0f, fromVis) + assignAnimValues("init", 0f, from.visibility) } } @@ -251,31 +278,23 @@ class ClockSizeTransition( } } - override fun mutateBounds( - view: View, - fromIsVis: Boolean, - toIsVis: Boolean, - fromBounds: Rect, - toBounds: Rect, - fromSSBounds: Rect?, - toSSBounds: Rect?, - ) { + override fun initTargets(from: Target, to: Target) { // Move normally if clock is not changing visibility - if (fromIsVis == toIsVis) return + if (from.isVisible == to.isVisible) return - fromBounds.set(toBounds) + from.bounds.set(to.bounds) if (isLargeClock) { // Large clock shouldn't move; fromBounds already set - } else if (toSSBounds != null && fromSSBounds != null) { + } else if (to.ssBounds != null && from.ssBounds != null) { // Instead of moving the small clock the full distance, we compute the distance // smartspace will move. We then scale this to match the duration of this animation // so that the small clock moves at the same speed as smartspace. val ssTranslation = - abs((toSSBounds.top - fromSSBounds.top) * smallClockMoveScale).toInt() - fromBounds.top = toBounds.top - ssTranslation - fromBounds.bottom = toBounds.bottom - ssTranslation + abs((to.ssBounds!!.top - from.ssBounds!!.top) * smallClockMoveScale).toInt() + from.bounds.top = to.bounds.top - ssTranslation + from.bounds.bottom = to.bounds.bottom - ssTranslation } else { - Log.e(TAG, "mutateBounds: smallClock received no smartspace bounds") + Log.e(TAG, "initTargets: smallClock received no smartspace bounds") } } } @@ -320,10 +339,9 @@ class ClockSizeTransition( } } - // TODO: Might need a mechanism to update this one while in-progress class SmartspaceMoveTransition( val config: IntraBlueprintTransition.Config, - viewModel: KeyguardClockViewModel, + val viewModel: KeyguardClockViewModel, ) : VisibilityBoundsTransition() { private val isLargeClock = viewModel.isLargeClockVisible.value override val captureSmartspace = false @@ -340,23 +358,23 @@ class ClockSizeTransition( addTarget(R.id.status_view_media_container) } - override fun mutateBounds( - view: View, - fromIsVis: Boolean, - toIsVis: Boolean, - fromBounds: Rect, - toBounds: Rect, - fromSSBounds: Rect?, - toSSBounds: Rect?, - ) { + override fun initTargets(from: Target, to: Target) { // If view is changing visibility, hold it in place - if (fromIsVis == toIsVis) return - if (DEBUG) Log.i(TAG, "Holding position of ${view.id}") + if (from.isVisible == to.isVisible) return + if (DEBUG) Log.i(TAG, "Holding position of ${to.view.id}") - if (fromIsVis) { - toBounds.set(fromBounds) + if (from.isVisible) { + to.bounds.set(from.bounds) } else { - fromBounds.set(toBounds) + from.bounds.set(to.bounds) + } + } + + override fun mutateTargets(from: Target, to: Target) { + if (to.view.id == sharedR.id.date_smartspace_view) { + to.isVisible = !viewModel.hasCustomWeatherDataDisplay.value + to.visibility = if (to.isVisible) View.VISIBLE else View.GONE + to.alpha = if (to.isVisible) 1f else 0f } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModel.kt index e68e465ed55a..ba03c48c65e9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModel.kt @@ -16,10 +16,50 @@ package com.android.systemui.keyguard.ui.viewmodel +import androidx.compose.runtime.getValue +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.lifecycle.Hydrator import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor -import javax.inject.Inject -import kotlinx.coroutines.flow.StateFlow +import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.flowOf -class KeyguardMediaViewModel @Inject constructor(mediaCarouselInteractor: MediaCarouselInteractor) { - val isMediaVisible: StateFlow<Boolean> = mediaCarouselInteractor.hasActiveMediaOrRecommendation +class KeyguardMediaViewModel +@AssistedInject +constructor( + mediaCarouselInteractor: MediaCarouselInteractor, + keyguardInteractor: KeyguardInteractor, +) : ExclusiveActivatable() { + + private val hydrator = Hydrator("KeyguardMediaViewModel.hydrator") + /** + * Whether media carousel is visible on lockscreen. Media may be presented on lockscreen but + * still hidden on certain surfaces like AOD + */ + val isMediaVisible: Boolean by + hydrator.hydratedStateOf( + traceName = "isMediaVisible", + source = + keyguardInteractor.isDozing.flatMapLatestConflated { isDozing -> + if (isDozing) { + flowOf(false) + } else { + mediaCarouselInteractor.hasActiveMediaOrRecommendation + } + }, + initialValue = + !keyguardInteractor.isDozing.value && + mediaCarouselInteractor.hasActiveMediaOrRecommendation.value, + ) + + override suspend fun onActivated(): Nothing { + hydrator.activate() + } + + @AssistedFactory + interface Factory { + fun create(): KeyguardMediaViewModel + } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java index 8f04896fbb45..645bd0b4b441 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java @@ -18,6 +18,7 @@ package com.android.systemui.navigationbar; import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG; import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen; +import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement; import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification; import static com.android.wm.shell.Flags.enableTaskbarOnPhones; @@ -273,6 +274,11 @@ public class NavigationBarControllerImpl implements private final CommandQueue.Callbacks mCommandQueueCallbacks = new CommandQueue.Callbacks() { @Override public void onDisplayRemoved(int displayId) { + onDisplayRemoveSystemDecorations(displayId); + } + + @Override + public void onDisplayRemoveSystemDecorations(int displayId) { removeNavigationBar(displayId); mHasNavBar.delete(displayId); } @@ -309,6 +315,13 @@ public class NavigationBarControllerImpl implements navBarView.showPinningEscapeToast(); } } + + @Override + public void setHasNavigationBar(int displayId, boolean hasNavigationBar) { + if (enableDisplayContentModeManagement()) { + mHasNavBar.put(displayId, hasNavigationBar); + } + } }; /** diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java index 9270fff61c43..05d8bff2ceb6 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java @@ -17,7 +17,7 @@ package com.android.systemui.navigationbar; import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; -import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; +import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; @@ -361,7 +361,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, mSysUiState.setFlag(SYSUI_STATE_A11Y_BUTTON_CLICKABLE, clickable) .setFlag(SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE, longClickable) .setFlag(SYSUI_STATE_IME_SHOWING, - (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0) + (mNavigationIconHints & NAVIGATION_HINT_IME_SHOWN) != 0) .setFlag(SYSUI_STATE_IME_SWITCHER_SHOWING, (mNavigationIconHints & NAVIGATION_HINT_IME_SWITCHER_SHOWN) != 0) .setFlag(SYSUI_STATE_OVERVIEW_DISABLED, diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java index c098b1675b87..c78750718cf0 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java @@ -17,7 +17,7 @@ package com.android.systemui.navigationbar.views; import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; -import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; +import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN; import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; @@ -1681,7 +1681,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements .setFlag(SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE, longClickable) .setFlag(SYSUI_STATE_NAV_BAR_HIDDEN, !isNavBarWindowVisible()) .setFlag(SYSUI_STATE_IME_SHOWING, - (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0) + (mNavigationIconHints & NAVIGATION_HINT_IME_SHOWN) != 0) .setFlag(SYSUI_STATE_IME_SWITCHER_SHOWING, (mNavigationIconHints & NAVIGATION_HINT_IME_SWITCHER_SHOWN) != 0) .setFlag(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY, @@ -1938,9 +1938,9 @@ public class NavigationBar extends ViewController<NavigationBarView> implements final boolean oldBackAlt = (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0; if (newBackAlt != oldBackAlt) { - mView.onImeVisibilityChanged(newBackAlt); - mImeVisible = newBackAlt; + mView.onBackAltChanged(newBackAlt); } + mImeVisible = (hints & NAVIGATION_HINT_IME_SHOWN) != 0; mView.setNavigationIconHints(hints); } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarView.java index c4abcd2afc4f..d5ae72165c4a 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarView.java @@ -561,8 +561,15 @@ public class NavigationBarView extends FrameLayout { updateNavButtonIcons(); } - void onImeVisibilityChanged(boolean visible) { - if (!visible) { + /** + * Called when the boolean value of whether to adjust the back button for the IME changed. + * + * @param useBackAlt whether to adjust the back button for the IME. + * + * @see android.inputmethodservice.InputMethodService.BackDispositionMode + */ + void onBackAltChanged(boolean useBackAlt) { + if (!useBackAlt) { mTransitionListener.onBackAltCleared(); } } diff --git a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt index 4fe63379aed4..8aad61a8c7cb 100644 --- a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt @@ -52,6 +52,13 @@ constructor( private val hydrator = Hydrator("NotificationsShadeOverlayContentViewModel.hydrator") + val isShadeLayoutWide: Boolean by + hydrator.hydratedStateOf( + traceName = "isShadeLayoutWide", + initialValue = shadeInteractor.isShadeLayoutWide.value, + source = shadeInteractor.isShadeLayoutWide, + ) + val showHeader: Boolean by hydrator.hydratedStateOf( traceName = "showHeader", diff --git a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeUserActionsViewModel.kt deleted file mode 100644 index 398ace4b67f4..000000000000 --- a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeUserActionsViewModel.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.notifications.ui.viewmodel - -import com.android.compose.animation.scene.Back -import com.android.compose.animation.scene.Swipe -import com.android.compose.animation.scene.UserAction -import com.android.compose.animation.scene.UserActionResult -import com.android.compose.animation.scene.UserActionResult.ReplaceByOverlay -import com.android.systemui.scene.shared.model.Overlays -import com.android.systemui.scene.shared.model.SceneFamilies -import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge -import com.android.systemui.scene.ui.viewmodel.UserActionsViewModel -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject - -/** - * Models the UI state for the user actions that the user can perform to navigate to other scenes. - */ -class NotificationsShadeUserActionsViewModel @AssistedInject constructor() : - UserActionsViewModel() { - - override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) { - setActions( - mapOf( - Back to SceneFamilies.Home, - Swipe.Up to SceneFamilies.Home, - Swipe.Down(fromSource = SceneContainerEdge.TopRight) to - ReplaceByOverlay(Overlays.QuickSettingsShade), - ) - ) - } - - @AssistedFactory - interface Factory { - fun create(): NotificationsShadeUserActionsViewModel - } -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt b/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt index 3fd9803882ed..4a9e72f23446 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt @@ -30,6 +30,7 @@ import javax.inject.Inject import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.shade.ShadeViewProviderModule.Companion.SHADE_HEADER +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor import com.android.systemui.statusbar.policy.DeviceProvisionedController import javax.inject.Named @@ -63,7 +64,8 @@ class HeaderPrivacyIconsController @Inject constructor( private val broadcastDispatcher: BroadcastDispatcher, private val safetyCenterManager: SafetyCenterManager, private val deviceProvisionedController: DeviceProvisionedController, - private val featureFlags: FeatureFlags + private val featureFlags: FeatureFlags, + private val shadeDialogContextInteractor: ShadeDialogContextInteractor, ) { var chipVisibilityListener: ChipVisibilityListener? = null @@ -75,6 +77,8 @@ class HeaderPrivacyIconsController @Inject constructor( private val cameraSlot = privacyChip.resources.getString(R.string.status_bar_camera) private val micSlot = privacyChip.resources.getString(R.string.status_bar_microphone) private val locationSlot = privacyChip.resources.getString(R.string.status_bar_location) + private val dialogContext: Context + get() = shadeDialogContextInteractor.context private val safetyCenterReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { @@ -149,12 +153,12 @@ class HeaderPrivacyIconsController @Inject constructor( uiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_CLICK) if (safetyCenterEnabled) { if (featureFlags.isEnabled(Flags.ENABLE_NEW_PRIVACY_DIALOG)) { - privacyDialogControllerV2.showDialog(privacyChip.context, privacyChip) + privacyDialogControllerV2.showDialog(dialogContext, privacyChip) } else { showSafetyCenter() } } else { - privacyDialogController.showDialog(privacyChip.context) + privacyDialogController.showDialog(dialogContext) } } setChipVisibility(privacyChip.visibility == View.VISIBLE) diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt index 6d9078432ae0..07de4662e82f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt @@ -102,6 +102,7 @@ import com.android.compose.modifiers.thenIf import com.android.compose.theme.PlatformTheme import com.android.mechanics.GestureContext import com.android.systemui.Dumpable +import com.android.systemui.Flags import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.dump.DumpManager @@ -252,12 +253,14 @@ constructor( Box( modifier = Modifier.graphicsLayer { alpha = viewModel.viewAlpha } - // Clipping before translation to match QSContainerImpl.onDraw - .offset { - IntOffset( - x = 0, - y = viewModel.viewTranslationY.fastRoundToInt(), - ) + .thenIf(!Flags.notificationShadeBlur()) { + // Clipping before translation to match QSContainerImpl.onDraw + Modifier.offset { + IntOffset( + x = 0, + y = viewModel.viewTranslationY.fastRoundToInt(), + ) + } } .thenIf(notificationScrimClippingParams.isEnabled) { Modifier.notificationScrimClip { diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt index c9d767e6d152..302242ca11dd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt @@ -16,7 +16,7 @@ package com.android.systemui.qs.panels.ui.compose -import android.processor.immutability.Immutable +import androidx.compose.runtime.Stable import com.android.compose.animation.Bounceable import com.android.systemui.qs.panels.shared.model.SizedTile import com.android.systemui.qs.panels.ui.model.GridCell @@ -24,7 +24,7 @@ import com.android.systemui.qs.panels.ui.model.TileGridCell import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel -@Immutable +@Stable data class BounceableInfo( val bounceable: BounceableTileViewModel, val previousTile: Bounceable?, diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt index 5cb30b999e13..b084f79a5bba 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt @@ -19,8 +19,8 @@ package com.android.systemui.qs.panels.ui.compose import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.key import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier @@ -49,6 +49,8 @@ fun ContentScope.QuickQuickSettings( val squishiness by viewModel.squishinessViewModel.squishiness.collectAsStateWithLifecycle() val scope = rememberCoroutineScope() + val spans by remember(sizedTiles) { derivedStateOf { sizedTiles.fastMap { it.width } } } + DisposableEffect(tiles) { val token = Any() tiles.forEach { it.startListening(token) } @@ -62,26 +64,24 @@ fun ContentScope.QuickQuickSettings( columns = columns, columnSpacing = dimensionResource(R.dimen.qs_tile_margin_horizontal), rowSpacing = dimensionResource(R.dimen.qs_tile_margin_vertical), - spans = sizedTiles.fastMap { it.width }, + spans = spans, modifier = Modifier.sysuiResTag("qqs_tile_layout"), + keys = { sizedTiles[it].tile.spec }, ) { spanIndex -> val it = sizedTiles[spanIndex] val column = cellIndex % columns cellIndex += it.width - key(it.tile.spec) { - Tile( - tile = it.tile, - iconOnly = it.isIcon, - modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)), - squishiness = { squishiness }, - coroutineScope = scope, - bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns), - tileHapticsViewModelFactoryProvider = - viewModel.tileHapticsViewModelFactoryProvider, - // There should be no QuickQuickSettings when the details view is enabled. - detailsViewModel = null, - ) - } + Tile( + tile = it.tile, + iconOnly = it.isIcon, + modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)), + squishiness = { squishiness }, + coroutineScope = scope, + bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns), + tileHapticsViewModelFactoryProvider = viewModel.tileHapticsViewModelFactoryProvider, + // There should be no QuickQuickSettings when the details view is enabled. + detailsViewModel = null, + ) } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt index 1bfbbe1964dc..30fb50db82a2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileDetails.kt @@ -38,12 +38,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.em import com.android.systemui.qs.flags.QsDetailedView import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel @Composable -fun TileDetails(detailsViewModel: DetailsViewModel) { +fun TileDetails(modifier: Modifier = Modifier, detailsViewModel: DetailsViewModel) { if (!QsDetailedView.isEnabled) { throw IllegalStateException("QsDetailedView should be enabled") @@ -54,10 +53,11 @@ fun TileDetails(detailsViewModel: DetailsViewModel) { DisposableEffect(Unit) { onDispose { detailsViewModel.closeDetailedView() } } Column( - modifier = Modifier - .fillMaxWidth() - // The height of the details view is TBD. - .fillMaxHeight() + modifier = + modifier + .fillMaxWidth() + // The height of the details view is TBD. + .fillMaxHeight() ) { CompositionLocalProvider( value = LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant @@ -65,15 +65,14 @@ fun TileDetails(detailsViewModel: DetailsViewModel) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically + verticalAlignment = Alignment.CenterVertically, ) { - IconButton( onClick = { detailsViewModel.closeDetailedView() }, - modifier = Modifier - .align(Alignment.CenterVertically) - .height(TileDetailsDefaults.IconHeight) - .padding(start = TileDetailsDefaults.IconPadding), + modifier = + Modifier.align(Alignment.CenterVertically) + .height(TileDetailsDefaults.IconHeight) + .padding(start = TileDetailsDefaults.IconPadding), ) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, @@ -83,17 +82,16 @@ fun TileDetails(detailsViewModel: DetailsViewModel) { } Text( text = tileDetailedViewModel.getTitle(), - modifier = Modifier - .align(Alignment.CenterVertically), + modifier = Modifier.align(Alignment.CenterVertically), textAlign = TextAlign.Center, - style = MaterialTheme.typography.titleLarge + style = MaterialTheme.typography.titleLarge, ) IconButton( onClick = { tileDetailedViewModel.clickOnSettingsButton() }, - modifier = Modifier - .align(Alignment.CenterVertically) - .height(TileDetailsDefaults.IconHeight) - .padding(end = TileDetailsDefaults.IconPadding), + modifier = + Modifier.align(Alignment.CenterVertically) + .height(TileDetailsDefaults.IconHeight) + .padding(end = TileDetailsDefaults.IconPadding), ) { Icon( imageVector = Icons.Default.Settings, @@ -104,11 +102,9 @@ fun TileDetails(detailsViewModel: DetailsViewModel) { } Text( text = tileDetailedViewModel.getSubTitle(), - modifier = Modifier - .fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center, - style = MaterialTheme.typography.titleSmall - + style = MaterialTheme.typography.titleSmall, ) } tileDetailedViewModel.GetContentView() diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt index 4432d336237f..cc4c3af1dc63 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt @@ -18,8 +18,8 @@ package com.android.systemui.qs.panels.ui.compose.infinitegrid import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.key import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier @@ -86,27 +86,28 @@ constructor( val scope = rememberCoroutineScope() var cellIndex = 0 + val spans by remember(sizedTiles) { derivedStateOf { sizedTiles.fastMap { it.width } } } + VerticalSpannedGrid( columns = columns, columnSpacing = dimensionResource(R.dimen.qs_tile_margin_horizontal), rowSpacing = dimensionResource(R.dimen.qs_tile_margin_vertical), - spans = sizedTiles.fastMap { it.width }, + spans = spans, + keys = { sizedTiles[it].tile.spec }, ) { spanIndex -> val it = sizedTiles[spanIndex] val column = cellIndex % columns cellIndex += it.width - key(it.tile.spec) { - Tile( - tile = it.tile, - iconOnly = iconTilesViewModel.isIconTile(it.tile.spec), - modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)), - squishiness = { squishiness }, - tileHapticsViewModelFactoryProvider = tileHapticsViewModelFactoryProvider, - coroutineScope = scope, - bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns), - detailsViewModel = detailsViewModel, - ) - } + Tile( + tile = it.tile, + iconOnly = iconTilesViewModel.isIconTile(it.tile.spec), + modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)), + squishiness = { squishiness }, + tileHapticsViewModelFactoryProvider = tileHapticsViewModelFactoryProvider, + coroutineScope = scope, + bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns), + detailsViewModel = detailsViewModel, + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt index 16c27223a471..8a627c452081 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt @@ -18,6 +18,7 @@ package com.android.systemui.qs.pipeline.shared import android.content.ComponentName import android.text.TextUtils +import androidx.compose.runtime.Stable import com.android.systemui.qs.external.CustomTile /** @@ -34,6 +35,7 @@ sealed class TileSpec private constructor(open val spec: String) { data object Invalid : TileSpec("") /** Container for the spec of a tile provided by SystemUI. */ + @Stable data class PlatformTileSpec internal constructor(override val spec: String) : TileSpec(spec) { override fun toString(): String { return "P($spec)" @@ -45,6 +47,7 @@ sealed class TileSpec private constructor(open val spec: String) { * * [componentName] indicates the associated `TileService`. */ + @Stable data class CustomTileSpec internal constructor(override val spec: String, val componentName: ComponentName) : TileSpec(spec) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt index 91d907952bc6..c7db04a6b7b2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt @@ -16,6 +16,7 @@ package com.android.systemui.qs.ui.viewmodel +import androidx.compose.runtime.getValue import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel @@ -23,6 +24,7 @@ import com.android.systemui.qs.panels.ui.viewmodel.EditModeViewModel import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel import com.android.systemui.qs.panels.ui.viewmodel.toolbar.ToolbarViewModel +import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -35,6 +37,7 @@ class QuickSettingsContainerViewModel constructor( brightnessSliderViewModelFactory: BrightnessSliderViewModel.Factory, quickQuickSettingsViewModelFactory: QuickQuickSettingsViewModel.Factory, + shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory, @Assisted supportsBrightnessMirroring: Boolean, val tileGridViewModel: TileGridViewModel, val editModeViewModel: EditModeViewModel, @@ -47,10 +50,13 @@ constructor( val quickQuickSettingsViewModel = quickQuickSettingsViewModelFactory.create() + val shadeHeaderViewModel = shadeHeaderViewModelFactory.create() + override suspend fun onActivated(): Nothing { coroutineScope { launch { brightnessSliderViewModel.activate() } launch { quickQuickSettingsViewModel.activate() } + launch { shadeHeaderViewModel.activate() } awaitCancellation() } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt index a108bc2c4a8c..d9df1ef36847 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt @@ -52,6 +52,13 @@ constructor( private val hydrator = Hydrator("QuickSettingsContainerViewModel.hydrator") + val isShadeLayoutWide: Boolean by + hydrator.hydratedStateOf( + traceName = "isShadeLayoutWide", + initialValue = shadeInteractor.isShadeLayoutWide.value, + source = shadeInteractor.isShadeLayoutWide, + ) + val showHeader: Boolean by hydrator.hydratedStateOf( traceName = "showHeader", @@ -61,6 +68,13 @@ constructor( val quickSettingsContainerViewModel = quickSettingsContainerViewModelFactory.create(false) + val showQuickSettingsOverlayHeader: Boolean by + hydrator.hydratedStateOf( + traceName = "showQuickSettingsOverlayHeader", + initialValue = shadeInteractor.isShadeLayoutWide.value, + source = shadeInteractor.isShadeLayoutWide, + ) + override suspend fun onActivated(): Nothing { coroutineScope { launch { hydrator.activate() } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index adf9eb44e162..60c2cca1ae8b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -61,7 +61,6 @@ import android.os.IBinder; import android.os.IRemoteCallback; import android.os.Looper; import android.os.PatternMatcher; -import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; @@ -100,6 +99,7 @@ import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.navigationbar.views.NavigationBar; import com.android.systemui.navigationbar.views.NavigationBarView; import com.android.systemui.navigationbar.views.buttons.KeyButtonView; +import com.android.systemui.process.ProcessWrapper; import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; import com.android.systemui.scene.domain.interactor.SceneInteractor; import com.android.systemui.scene.shared.flag.SceneContainerFlag; @@ -675,11 +675,12 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis DumpManager dumpManager, Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder, BroadcastDispatcher broadcastDispatcher, - Optional<BackAnimation> backAnimation + Optional<BackAnimation> backAnimation, + ProcessWrapper processWrapper ) { // b/241601880: This component should only be running for primary users or // secondaryUsers when visibleBackgroundUsers are supported. - boolean isSystemUser = Process.myUserHandle().equals(UserHandle.SYSTEM); + boolean isSystemUser = processWrapper.isSystemUser(); boolean isVisibleBackgroundUser = userManager.isVisibleBackgroundUsersSupported() && !userManager.isUserForeground(); if (!isSystemUser && isVisibleBackgroundUser) { diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt index 2a0a22f32601..6e79d568761f 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt @@ -18,6 +18,7 @@ package com.android.systemui.scene.domain.resolver +import android.util.Log import com.android.compose.animation.scene.SceneKey import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -85,8 +86,8 @@ constructor( isUnlocked: Boolean, isDreamingWithOverlay: Boolean, isAbleToDream: Boolean, - ): SceneKey = - when { + ): SceneKey { + val result = when { // Dream can run even if Keyguard is disabled, thus it has the highest priority here. isDreamingWithOverlay && isAbleToDream -> Scenes.Dream !isKeyguardEnabled -> Scenes.Gone @@ -95,8 +96,21 @@ constructor( !isUnlocked -> Scenes.Lockscreen else -> Scenes.Gone } + Log.d(TAG, "homeScene emitting $result, values:") + Log.d(TAG, " isKeyguardEnabled=$isKeyguardEnabled") + Log.d(TAG, " canSwipeToEnter=$canSwipeToEnter") + Log.d(TAG, " isDeviceEntered=$isDeviceEntered" ) + Log.d(TAG, " isUnlocked=$isUnlocked") + Log.d(TAG, " isDreamingWithOverlay=$isDreamingWithOverlay") + Log.d(TAG, " isAbleToDream=$isAbleToDream") + Log.d(TAG, "") + return result + } companion object { + + private const val TAG = "HomeSceneFamilyResolver" + val homeScenes = setOf( Scenes.Gone, diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt index 8657c1723507..ecd002705c60 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt @@ -564,7 +564,7 @@ constructor( .collect { switchToScene( targetSceneKey = Scenes.Lockscreen, - loggingReason = "device became non-interactive", + loggingReason = "device became non-interactive (SceneContainerStartable)", ) } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt index 747642097327..f926d39760fe 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt @@ -36,7 +36,6 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.res.R import com.android.systemui.scene.ui.view.WindowRootView -import com.android.systemui.shade.data.repository.MutableShadeDisplaysRepository import com.android.systemui.shade.data.repository.ShadeDisplaysRepository import com.android.systemui.shade.data.repository.ShadeDisplaysRepositoryImpl import com.android.systemui.shade.display.ShadeDisplayPolicyModule @@ -211,15 +210,6 @@ object ShadeDisplayAwareModule { return impl } - @SysUISingleton - @Provides - fun provideMutableShadePositionRepository( - impl: ShadeDisplaysRepositoryImpl - ): MutableShadeDisplaysRepository { - ShadeWindowGoesAround.isUnexpectedlyInLegacyMode() - return impl - } - @Provides @SysUISingleton fun provideShadeDialogContextInteractor( diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt index ec9bba7c1f0f..13b540aa54ba 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayChangeLatencyTracker.kt @@ -16,7 +16,6 @@ package com.android.systemui.shade import android.util.Log -import android.view.Display import com.android.app.tracing.coroutines.TrackTracer import com.android.internal.util.LatencyTracker import com.android.systemui.common.ui.data.repository.ConfigurationRepository @@ -32,11 +31,9 @@ import javax.inject.Inject import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeout @@ -73,12 +70,7 @@ constructor( /** * We need to keep this always up to date eagerly to avoid delays receiving the new display ID. */ - private val onMovedToDisplayFlow: StateFlow<Int> = - configurationRepository.onMovedToDisplay.stateIn( - bgScope, - SharingStarted.Eagerly, - Display.DEFAULT_DISPLAY, - ) + private val onMovedToDisplayFlow: StateFlow<Int> = configurationRepository.onMovedToDisplay private var previousJob: Job? = null diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt index 7bfe40c3d811..173da336c62f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt @@ -20,7 +20,7 @@ import android.provider.Settings.Global.DEVELOPMENT_SHADE_DISPLAY_AWARENESS import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.display.data.repository.DisplayRepository -import com.android.systemui.shade.data.repository.MutableShadeDisplaysRepository +import com.android.systemui.shade.data.repository.ShadeDisplaysRepository import com.android.systemui.shade.display.ShadeDisplayPolicy import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry @@ -35,7 +35,7 @@ constructor( private val globalSettings: GlobalSettings, private val commandRegistry: CommandRegistry, private val displaysRepository: DisplayRepository, - private val positionRepository: MutableShadeDisplaysRepository, + private val positionRepository: ShadeDisplaysRepository, private val policies: Set<@JvmSuppressWildcards ShadeDisplayPolicy>, private val defaultPolicy: ShadeDisplayPolicy, ) : Command, CoreStartable { @@ -103,7 +103,7 @@ constructor( } private fun printPolicies() { - val currentPolicyName = positionRepository.policy.value.name + val currentPolicyName = positionRepository.currentPolicy.name pw.println("Available policies: ") policies.forEach { pw.print(" - ${it.name}") diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt index 732d4d1500e7..3513334f2a5c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt @@ -17,6 +17,8 @@ package com.android.systemui.shade.data.repository import android.view.Display +import com.android.systemui.shade.display.FakeShadeDisplayPolicy +import com.android.systemui.shade.display.ShadeDisplayPolicy import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -30,7 +32,6 @@ class FakeShadeDisplayRepository : ShadeDisplaysRepository { override val displayId: StateFlow<Int> get() = _displayId - fun resetDisplayId() { - _displayId.value = Display.DEFAULT_DISPLAY - } + override val currentPolicy: ShadeDisplayPolicy + get() = FakeShadeDisplayPolicy } diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt index af48231e0a99..f959f7fe0c31 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt @@ -20,14 +20,18 @@ import android.provider.Settings.Global.DEVELOPMENT_SHADE_DISPLAY_AWARENESS import android.view.Display import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.keyguard.data.repository.KeyguardRepository +import com.android.systemui.shade.ShadeOnDefaultDisplayWhenLocked import com.android.systemui.shade.display.ShadeDisplayPolicy import com.android.systemui.util.settings.GlobalSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map @@ -38,12 +42,8 @@ import kotlinx.coroutines.flow.stateIn interface ShadeDisplaysRepository { /** ID of the display which currently hosts the shade */ val displayId: StateFlow<Int> -} - -/** Allows to change the policy that determines in which display the Shade window is visible. */ -interface MutableShadeDisplaysRepository : ShadeDisplaysRepository { - /** Updates the policy to select where the shade is visible. */ - val policy: StateFlow<ShadeDisplayPolicy> + /** The current policy set. */ + val currentPolicy: ShadeDisplayPolicy } /** Keeps the policy and propagates the display id for the shade from it. */ @@ -56,9 +56,11 @@ constructor( defaultPolicy: ShadeDisplayPolicy, @Background bgScope: CoroutineScope, policies: Set<@JvmSuppressWildcards ShadeDisplayPolicy>, -) : MutableShadeDisplaysRepository { + @ShadeOnDefaultDisplayWhenLocked private val shadeOnDefaultDisplayWhenLocked: Boolean, + keyguardRepository: KeyguardRepository, +) : ShadeDisplaysRepository { - override val policy: StateFlow<ShadeDisplayPolicy> = + private val policy: StateFlow<ShadeDisplayPolicy> = globalSettings .observerFlow(DEVELOPMENT_SHADE_DISPLAY_AWARENESS) .onStart { emit(Unit) } @@ -71,10 +73,32 @@ constructor( return@map defaultPolicy } .distinctUntilChanged() - .stateIn(bgScope, SharingStarted.WhileSubscribed(), defaultPolicy) + .stateIn(bgScope, SharingStarted.Eagerly, defaultPolicy) + + private val displayIdFromPolicy: Flow<Int> = policy.flatMapLatest { it.displayId } + + private val keyguardAwareDisplayPolicy: Flow<Int> = + if (!shadeOnDefaultDisplayWhenLocked) { + displayIdFromPolicy + } else { + keyguardRepository.isKeyguardShowing.combine(displayIdFromPolicy) { + isKeyguardShowing, + currentDisplayId -> + if (isKeyguardShowing) { + Display.DEFAULT_DISPLAY + } else { + currentDisplayId + } + } + } + + override val currentPolicy: ShadeDisplayPolicy + get() = policy.value override val displayId: StateFlow<Int> = - policy - .flatMapLatest { it.displayId } - .stateIn(bgScope, SharingStarted.WhileSubscribed(), Display.DEFAULT_DISPLAY) + keyguardAwareDisplayPolicy.stateIn( + bgScope, + SharingStarted.WhileSubscribed(), + Display.DEFAULT_DISPLAY, + ) } diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/FakeShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/FakeShadeDisplayPolicy.kt new file mode 100644 index 000000000000..e010bd6f9880 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/display/FakeShadeDisplayPolicy.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade.display + +import android.view.Display +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +/** Used only for testing. */ +object FakeShadeDisplayPolicy : ShadeDisplayPolicy { + override val name: String + get() = "fake_shade_policy" + + override val displayId: StateFlow<Int> + get() = _displayId + + private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY) + + fun setDisplayId(displayId: Int) { + _displayId.value = displayId + } +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/FocusShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/FocusShadeDisplayPolicy.kt new file mode 100644 index 000000000000..7d8f7c59ad66 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/display/FocusShadeDisplayPolicy.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade.display + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.display.data.repository.FocusedDisplayRepository +import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow + +/** Policy that just emits the [FocusedDisplayRepository] display id. */ +@SysUISingleton +class FocusShadeDisplayPolicy +@Inject +constructor(private val focusedDisplayRepository: FocusedDisplayRepository) : ShadeDisplayPolicy { + override val name: String + get() = "focused_display" + + override val displayId: StateFlow<Int> + get() = focusedDisplayRepository.focusedDisplayId +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt index d53f9f7ec595..677e41a47afe 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt @@ -19,7 +19,8 @@ package com.android.systemui.shade.display import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor.ShadeElement import dagger.Binds import dagger.Module -import dagger.multibindings.IntoSet +import dagger.Provides +import dagger.multibindings.ElementsIntoSet import kotlinx.coroutines.flow.StateFlow /** Describes the display the shade should be shown in. */ @@ -53,27 +54,25 @@ interface ShadeExpansionIntent { fun consumeExpansionIntent(): ShadeElement? } -@Module +@Module(includes = [AllShadeDisplayPoliciesModule::class]) interface ShadeDisplayPolicyModule { - @Binds fun provideDefaultPolicy(impl: StatusBarTouchShadeDisplayPolicy): ShadeDisplayPolicy + @Binds fun provideDefaultPolicy(impl: DefaultDisplayShadePolicy): ShadeDisplayPolicy @Binds fun provideShadeExpansionIntent(impl: StatusBarTouchShadeDisplayPolicy): ShadeExpansionIntent +} - @IntoSet - @Binds - fun provideDefaultDisplayPolicyToSet(impl: DefaultDisplayShadePolicy): ShadeDisplayPolicy - - @IntoSet - @Binds - fun provideAnyExternalShadeDisplayPolicyToSet( - impl: AnyExternalShadeDisplayPolicy - ): ShadeDisplayPolicy - - @Binds - @IntoSet - fun provideStatusBarTouchShadeDisplayPolicy( - impl: StatusBarTouchShadeDisplayPolicy - ): ShadeDisplayPolicy +@Module +internal object AllShadeDisplayPoliciesModule { + @Provides + @ElementsIntoSet + fun provideShadeDisplayPolicies( + defaultPolicy: DefaultDisplayShadePolicy, + externalPolicy: AnyExternalShadeDisplayPolicy, + statusBarPolicy: StatusBarTouchShadeDisplayPolicy, + focusPolicy: FocusShadeDisplayPolicy, + ): Set<ShadeDisplayPolicy> { + return setOf(defaultPolicy, externalPolicy, statusBarPolicy, focusPolicy) + } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt index 91020aa7bdb0..b155ada87efd 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt @@ -23,8 +23,6 @@ import com.android.app.tracing.coroutines.launchTraced import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.display.data.repository.DisplayRepository -import com.android.systemui.keyguard.data.repository.KeyguardRepository -import com.android.systemui.shade.ShadeOnDefaultDisplayWhenLocked import com.android.systemui.shade.domain.interactor.NotificationShadeElement import com.android.systemui.shade.domain.interactor.QSShadeElement import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor.ShadeElement @@ -38,13 +36,10 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn /** * Moves the shade on the last display that received a status bar touch. @@ -57,9 +52,7 @@ class StatusBarTouchShadeDisplayPolicy @Inject constructor( displayRepository: DisplayRepository, - keyguardRepository: KeyguardRepository, @Background private val backgroundScope: CoroutineScope, - @ShadeOnDefaultDisplayWhenLocked private val shadeOnDefaultDisplayWhenLocked: Boolean, private val shadeInteractor: Lazy<ShadeInteractor>, private val qsShadeElement: Lazy<QSShadeElement>, private val notificationElement: Lazy<NotificationShadeElement>, @@ -72,20 +65,7 @@ constructor( private var latestIntent = AtomicReference<ShadeElement?>() private var timeoutJob: Job? = null - override val displayId: StateFlow<Int> = - if (shadeOnDefaultDisplayWhenLocked) { - keyguardRepository.isKeyguardShowing - .combine(currentDisplayId) { isKeyguardShowing, currentDisplayId -> - if (isKeyguardShowing) { - Display.DEFAULT_DISPLAY - } else { - currentDisplayId - } - } - .stateIn(backgroundScope, SharingStarted.WhileSubscribed(), currentDisplayId.value) - } else { - currentDisplayId - } + override val displayId: StateFlow<Int> = currentDisplayId private var removalListener: Job? = null diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PrivacyChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PrivacyChipInteractor.kt index 4c6c31809275..0caeead17cd5 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PrivacyChipInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PrivacyChipInteractor.kt @@ -41,6 +41,7 @@ constructor( private val privacyDialogController: PrivacyDialogController, private val privacyDialogControllerV2: PrivacyDialogControllerV2, private val deviceProvisionedController: DeviceProvisionedController, + private val shadeDialogContextInteractor: ShadeDialogContextInteractor, ) { /** The list of PrivacyItems to be displayed by the privacy chip. */ val privacyItems: StateFlow<List<PrivacyItem>> = repository.privacyItems @@ -80,9 +81,9 @@ constructor( if (!deviceProvisionedController.isDeviceProvisioned) return if (repository.isSafetyCenterEnabled.value) { - privacyDialogControllerV2.showDialog(privacyChip.context, privacyChip) + privacyDialogControllerV2.showDialog(shadeDialogContextInteractor.context, privacyChip) } else { - privacyDialogController.showDialog(privacyChip.context) + privacyDialogController.showDialog(shadeDialogContextInteractor.context) } } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt index fc26499a27a7..b045db464674 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt @@ -20,24 +20,34 @@ import android.util.Log import android.window.WindowContext import androidx.annotation.UiThread import com.android.app.tracing.coroutines.launchTraced -import com.android.app.tracing.traceSection import com.android.systemui.CoreStartable +import com.android.systemui.common.ui.data.repository.ConfigurationRepository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shade.ShadeDisplayChangeLatencyTracker import com.android.systemui.shade.ShadeTraceLogger.logMoveShadeWindowTo +import com.android.systemui.shade.ShadeTraceLogger.t import com.android.systemui.shade.ShadeTraceLogger.traceReparenting import com.android.systemui.shade.data.repository.ShadeDisplaysRepository import com.android.systemui.shade.display.ShadeExpansionIntent import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround +import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor +import com.android.systemui.statusbar.notification.row.NotificationRebindingTracker +import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHider +import com.android.systemui.util.kotlin.getOrNull import com.android.window.flags.Flags import java.util.Optional import javax.inject.Inject import kotlin.coroutines.CoroutineContext +import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeoutOrNull /** Handles Shade window display change when [ShadeDisplaysRepository.displayId] changes. */ @SysUISingleton @@ -46,27 +56,29 @@ class ShadeDisplaysInteractor constructor( private val shadePositionRepository: ShadeDisplaysRepository, @ShadeDisplayAware private val shadeContext: WindowContext, + @ShadeDisplayAware private val configurationRepository: ConfigurationRepository, @Background private val bgScope: CoroutineScope, @Main private val mainThreadContext: CoroutineContext, private val shadeDisplayChangeLatencyTracker: ShadeDisplayChangeLatencyTracker, shadeExpandedInteractor: Optional<ShadeExpandedStateInteractor>, private val shadeExpansionIntent: ShadeExpansionIntent, + private val activeNotificationsInteractor: ActiveNotificationsInteractor, + private val notificationRebindingTracker: NotificationRebindingTracker, + notificationStackRebindingHider: Optional<NotificationStackRebindingHider>, ) : CoreStartable { - private val shadeExpandedInteractor = - shadeExpandedInteractor.orElse(null) - ?: error( - """ - ShadeExpandedStateInteractor must be provided for ShadeDisplaysInteractor to work. - If it is not, it means this is being instantiated in a SystemUI variant that shouldn't. - """ - .trimIndent() - ) + private val shadeExpandedInteractor = requireOptional(shadeExpandedInteractor) + private val notificationStackRebindingHider = requireOptional(notificationStackRebindingHider) + + private val hasActiveNotifications: Boolean + get() = activeNotificationsInteractor.areAnyNotificationsPresentValue override fun start() { ShadeWindowGoesAround.isUnexpectedlyInLegacyMode() bgScope.launchTraced(TAG) { - shadePositionRepository.displayId.collect { displayId -> moveShadeWindowTo(displayId) } + shadePositionRepository.displayId.collectLatest { displayId -> + moveShadeWindowTo(displayId) + } } } @@ -74,24 +86,22 @@ constructor( private suspend fun moveShadeWindowTo(destinationId: Int) { Log.d(TAG, "Trying to move shade window to display with id $destinationId") logMoveShadeWindowTo(destinationId) - // Why using the shade context here instead of the view's Display? - // The context's display is updated before the view one, so it is a better indicator of - // which display the shade is supposed to be at. The View display is updated after the first - // rendering with the new config. - val currentDisplay = shadeContext.display - if (currentDisplay == null) { - Log.w(TAG, "Current shade display is null") - return - } - val currentId = currentDisplay.displayId - if (currentId == destinationId) { - Log.w(TAG, "Trying to move the shade to a display it was already in") - return - } + var currentId = -1 try { + // Why using the shade context here instead of the view's Display? + // The context's display is updated before the view one, so it is a better indicator of + // which display the shade is supposed to be at. The View display is updated after the + // first + // rendering with the new config. + val currentDisplay = shadeContext.display ?: error("Current shade display is null") + currentId = currentDisplay.displayId + if (currentId == destinationId) { + error("Trying to move the shade to a display it was already in") + } + withContext(mainThreadContext) { traceReparenting { - collapseAndExpandShadeIfNeeded { + collapseAndExpandShadeIfNeeded(destinationId) { shadeDisplayChangeLatencyTracker.onShadeDisplayChanging(destinationId) reparentToDisplayId(id = destinationId) } @@ -107,16 +117,71 @@ constructor( } } - private suspend fun collapseAndExpandShadeIfNeeded(wrapped: () -> Unit) { + private suspend fun collapseAndExpandShadeIfNeeded(newDisplayId: Int, reparent: () -> Unit) { val previouslyExpandedElement = shadeExpandedInteractor.currentlyExpandedElement.value previouslyExpandedElement?.collapse(reason = COLLAPSE_EXPAND_REASON) + val notificationStackHidden = + if (!hasActiveNotifications) { + // This covers the case the previous move was cancelled before setting the + // visibility back. As there are no notifications, nothing can flicker here, and + // showing them all of a sudden is ok. + notificationStackRebindingHider.setVisible(visible = true, animated = false) + false + } else { + // Hiding as otherwise there might be flickers as the inflation with new dimensions + // happens async and views with the old dimensions are not removed until the + // inflation succeeds. + notificationStackRebindingHider.setVisible(visible = false, animated = false) + true + } - wrapped() + reparent() + val elementToExpand = + shadeExpansionIntent.consumeExpansionIntent() ?: previouslyExpandedElement // If the user was trying to expand a specific shade element, let's make sure to expand // that one. Otherwise, we can just re-expand the previous expanded element. - shadeExpansionIntent.consumeExpansionIntent()?.expand(COLLAPSE_EXPAND_REASON) - ?: previouslyExpandedElement?.expand(reason = COLLAPSE_EXPAND_REASON) + elementToExpand?.expand(COLLAPSE_EXPAND_REASON) + if (notificationStackHidden) { + if (hasActiveNotifications) { + // "onMovedToDisplay" is what synchronously triggers the rebinding of views: we need + // to wait for it to be received. + waitForOnMovedToDisplayDispatchedToView(newDisplayId) + waitForNotificationsRebinding() + } + notificationStackRebindingHider.setVisible(visible = true, animated = true) + } + } + + private suspend fun waitForOnMovedToDisplayDispatchedToView(newDisplayId: Int) { + withContext(bgScope.coroutineContext) { + t.traceAsync({ + "waitForOnMovedToDisplayDispatchedToView(newDisplayId=$newDisplayId)" + }) { + withTimeoutOrNull(TIMEOUT) { + configurationRepository.onMovedToDisplay.filter { it == newDisplayId }.first() + t.instant { "onMovedToDisplay received with $newDisplayId" } + } + ?: errorLog( + "Timed out while waiting for onMovedToDisplay to be dispatched to " + + "the shade root view in ShadeDisplaysInteractor" + ) + } + } + } + + private suspend fun waitForNotificationsRebinding() { + // here we don't need to wait for rebinding to appear (e.g. going > 0), as it already + // happened synchronously when the new configuration was received by ViewConfigCoordinator. + t.traceAsync("waiting for notifications rebinding to finish") { + withTimeoutOrNull(TIMEOUT) { + notificationRebindingTracker.rebindingInProgressCount.first { it == 0 } + } ?: errorLog("Timed out while waiting for inflations to finish") + } + } + + private fun errorLog(s: String) { + Log.e(TAG, s) } private fun checkContextDisplayMatchesExpected(destinationId: Int) { @@ -133,11 +198,33 @@ constructor( @UiThread private fun reparentToDisplayId(id: Int) { - traceSection({ "reparentToDisplayId(id=$id)" }) { shadeContext.reparentToDisplay(id) } + t.traceSyncAndAsync({ "reparentToDisplayId(id=$id)" }) { + shadeContext.reparentToDisplay(id) + } } private companion object { const val TAG = "ShadeDisplaysInteractor" const val COLLAPSE_EXPAND_REASON = "Shade window move" + val TIMEOUT = 1.seconds + + /** + * [ShadeDisplaysInteractor] is bound in the SystemUI module for all variants, but needs + * some specific dependencies to be bound from each variant (e.g. + * [ShadeExpandedStateInteractor] or [NotificationStackRebindingHider]). When those are not + * bound, this class is not expected to be instantiated, and trying to instantiate it would + * crash. + */ + inline fun <reified T> requireOptional(optional: Optional<T>): T { + return optional.getOrNull() + ?: error( + """ + ${T::class.java.simpleName} must be provided for ShadeDisplaysInteractor to work. + If it is not, it means this is being instantiated in a SystemUI variant that + shouldn't. + """ + .trimIndent() + ) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt index a653ca2f80a9..b5e171043741 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt @@ -16,6 +16,7 @@ package com.android.systemui.shade.domain.interactor +import android.util.Log import com.android.app.tracing.coroutines.flow.flowName import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -38,6 +39,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn /** The non-empty SceneInteractor implementation. */ @@ -98,18 +100,36 @@ constructor( override val isShadeTouchable: Flow<Boolean> = combine( - powerInteractor.isAsleep, - keyguardTransitionInteractor.isInTransition(Edge.create(to = KeyguardState.AOD)), - keyguardRepository.dozeTransitionModel.map { it.to == DozeStateModel.DOZE_PULSING }, - ) { isAsleep, goingToSleep, isPulsing -> - when { - // If the device is going to sleep, only accept touches if we're still - // animating - goingToSleep -> dozeParams.shouldControlScreenOff() + powerInteractor.isAsleep + .onEach { Log.d(TAG, "isShadeTouchable: upstream isAsleep=$it") }, + keyguardTransitionInteractor + .isInTransition(Edge.create(to = KeyguardState.AOD)) + .onEach { + Log.d( + TAG, + "isShadeTouchable: upstream isTransitioningToAod=$it", + ) + }, + keyguardRepository.dozeTransitionModel + .map { it.to == DozeStateModel.DOZE_PULSING } + .onEach { + Log.d(TAG, "isShadeTouchable: upstream isPulsing=$it") + }, + ) { isAsleep, isTransitioningToAod, isPulsing -> + val downstream = when { + // If the device is transitioning to AOD, only accept touches if + // still animating. + isTransitioningToAod -> dozeParams.shouldControlScreenOff() // If the device is asleep, only accept touches if there's a pulse isAsleep -> isPulsing else -> true } + Log.d(TAG, "isShadeTouchable emitting $downstream, values:") + Log.d(TAG, " isAsleep=$isAsleep") + Log.d(TAG, " isTransitioningToAod=$isTransitioningToAod") + Log.d(TAG, " isPulsing=$isPulsing") + Log.d(TAG, "") + downstream } override val isExpandToQsEnabled: Flow<Boolean> = @@ -128,4 +148,8 @@ constructor( disableFlags.isQuickSettingsEnabled() && !isDozing } + + companion object { + private const val TAG = "ShadeInteractor" + } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt index 765810810bb8..992385c8d80e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt @@ -199,11 +199,14 @@ constructor( ) } else if (transitionKey == Instant) { // TODO(b/356596436): Define instant transition instead of snapToScene(). - sceneInteractor.snapToScene(toScene = SceneFamilies.Home, loggingReason = loggingReason) + sceneInteractor.snapToScene( + toScene = SceneFamilies.Home, + loggingReason = loggingReason + " (collapseNotificationsShade)", + ) } else { sceneInteractor.changeScene( toScene = SceneFamilies.Home, - loggingReason = loggingReason, + loggingReason = loggingReason + " (collapseNotificationsShade)", transitionKey = transitionKey ?: ToSplitShade.takeIf { shadeModeInteractor.isSplitShade }, ) @@ -230,11 +233,14 @@ constructor( if (bypassNotificationsShade || isSplitShade) SceneFamilies.Home else Scenes.Shade if (transitionKey == Instant) { // TODO(b/356596436): Define instant transition instead of snapToScene(). - sceneInteractor.snapToScene(toScene = targetScene, loggingReason = loggingReason) + sceneInteractor.snapToScene( + toScene = targetScene, + loggingReason = loggingReason + " (collapseQuickSettingsShade)", + ) } else { sceneInteractor.changeScene( toScene = targetScene, - loggingReason = loggingReason, + loggingReason = loggingReason + " (collapseQuickSettingsShade)", transitionKey = transitionKey ?: ToSplitShade.takeIf { isSplitShade }, ) } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/ShadeColors.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/ShadeColors.kt new file mode 100644 index 000000000000..8db622566e5e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/ui/ShadeColors.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade.ui + +import android.content.res.Resources +import android.graphics.Color +import com.android.internal.graphics.ColorUtils +import com.android.systemui.res.R + +object ShadeColors { + @JvmStatic + fun Resources.shadePanel(): Int { + val layerAbove = + ColorUtils.setAlphaComponent(getColor(R.color.shade_panel_base), (0.4f * 255).toInt()) + val layerBelow = ColorUtils.setAlphaComponent(Color.WHITE, (0.1f * 255).toInt()) + return ColorUtils.compositeColors(layerAbove, layerBelow) + } + + @JvmStatic + fun Resources.notificationScrim(): Int { + return ColorUtils.setAlphaComponent( + getColor(R.color.notification_scrim_base), + (0.5f * 255).toInt(), + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt index 0d847d84c820..96128df1b723 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt @@ -23,18 +23,23 @@ import android.icu.text.DateFormat import android.icu.text.DisplayContext import android.os.UserHandle import android.provider.Settings +import androidx.compose.runtime.getValue import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.lifecycle.Hydrator import com.android.systemui.plugins.ActivityStarter import com.android.systemui.privacy.OngoingPrivacyChip import com.android.systemui.privacy.PrivacyItem import com.android.systemui.res.R +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shade.domain.interactor.PrivacyChipInteractor import com.android.systemui.shade.domain.interactor.ShadeHeaderClockInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor +import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel import dagger.assisted.AssistedFactory @@ -56,6 +61,7 @@ class ShadeHeaderViewModel constructor( @ShadeDisplayAware context: Context, private val activityStarter: ActivityStarter, + private val sceneInteractor: SceneInteractor, private val shadeInteractor: ShadeInteractor, private val mobileIconsInteractor: MobileIconsInteractor, val mobileIconsViewModel: MobileIconsViewModel, @@ -63,6 +69,35 @@ constructor( private val clockInteractor: ShadeHeaderClockInteractor, private val broadcastDispatcher: BroadcastDispatcher, ) : ExclusiveActivatable() { + private val hydrator = Hydrator("ShadeHeaderViewModel.hydrator") + + val highlightNotificationIcons: Boolean by + hydrator.hydratedStateOf( + traceName = "highlightNotificationIcons", + initialValue = false, + source = + sceneInteractor.currentOverlays.map { overlays -> + Overlays.NotificationsShade in overlays + }, + ) + + val highlightQuickSettingsIcons: Boolean by + hydrator.hydratedStateOf( + traceName = "highlightQuickSettingsIcons", + initialValue = false, + source = + sceneInteractor.currentOverlays.map { overlays -> + Overlays.QuickSettingsShade in overlays + }, + ) + + val isShadeLayoutWide: Boolean by + hydrator.hydratedStateOf( + traceName = "isShadeLayoutWide", + initialValue = shadeInteractor.isShadeLayoutWide.value, + source = shadeInteractor.isShadeLayoutWide, + ) + /** True if there is exactly one mobile connection. */ val isSingleCarrier: StateFlow<Boolean> = mobileIconsInteractor.isSingleCarrier @@ -128,6 +163,8 @@ constructor( .collect { _mobileSubIds.value = it } } + launch { hydrator.activate() } + awaitCancellation() } } @@ -143,11 +180,41 @@ constructor( } /** Notifies that the system icons container was clicked. */ - fun onSystemIconContainerClicked() { - shadeInteractor.collapseEitherShade( - loggingReason = "ShadeHeaderViewModel.onSystemIconContainerClicked", - transitionKey = SlightlyFasterShadeCollapse, - ) + fun onNotificationIconChipClicked() { + if (shadeInteractor.shadeMode.value !is ShadeMode.Dual) { + return + } + val loggingReason = "ShadeHeaderViewModel.onNotificationIconChipClicked" + val currentOverlays = sceneInteractor.currentOverlays.value + if (Overlays.NotificationsShade in currentOverlays) { + shadeInteractor.collapseNotificationsShade( + loggingReason = loggingReason, + transitionKey = SlightlyFasterShadeCollapse, + ) + } else { + shadeInteractor.expandNotificationsShade(loggingReason) + } + } + + /** Notifies that the system icons container was clicked. */ + fun onSystemIconChipClicked() { + val loggingReason = "ShadeHeaderViewModel.onSystemIconChipClicked" + if (shadeInteractor.shadeMode.value is ShadeMode.Dual) { + val currentOverlays = sceneInteractor.currentOverlays.value + if (Overlays.QuickSettingsShade in currentOverlays) { + shadeInteractor.collapseQuickSettingsShade( + loggingReason = loggingReason, + transitionKey = SlightlyFasterShadeCollapse, + ) + } else { + shadeInteractor.expandQuickSettingsShade(loggingReason) + } + } else { + shadeInteractor.collapseEitherShade( + loggingReason = loggingReason, + transitionKey = SlightlyFasterShadeCollapse, + ) + } } /** Notifies that the shadeCarrierGroup was clicked. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index c6a4d15705f0..7fc1510f1136 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -184,6 +184,8 @@ public class CommandQueue extends IStatusBar.Stub implements private static final int MSG_SET_SPLITSCREEN_FOCUS = 81 << MSG_SHIFT; private static final int MSG_TOGGLE_QUICK_SETTINGS_PANEL = 82 << MSG_SHIFT; private static final int MSG_WALLET_ACTION_LAUNCH_GESTURE = 83 << MSG_SHIFT; + private static final int MSG_SET_HAS_NAVIGATION_BAR = 84 << MSG_SHIFT; + private static final int MSG_DISPLAY_REMOVE_SYSTEM_DECORATIONS = 85 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1; @@ -419,6 +421,12 @@ public class CommandQueue extends IStatusBar.Stub implements } /** + * @see IStatusBar#onDisplayRemoveSystemDecorations(int) + */ + default void onDisplayRemoveSystemDecorations(int displayId) { + } + + /** * @see DisplayTracker.Callback#onDisplayRemoved(int) */ default void onDisplayRemoved(int displayId) { @@ -580,6 +588,12 @@ public class CommandQueue extends IStatusBar.Stub implements * @see IStatusBar#moveFocusedTaskToDesktop(int) */ default void moveFocusedTaskToDesktop(int displayId) {} + + /** + * @see IStatusBar#setHasNavigationBar(int, boolean) + */ + default void setHasNavigationBar(int displayId, boolean hasNavigationBar) { + } } @VisibleForTesting @@ -1197,6 +1211,14 @@ public class CommandQueue extends IStatusBar.Stub implements } } + @Override + public void onDisplayRemoveSystemDecorations(int displayId) { + synchronized (mLock) { + mHandler.obtainMessage(MSG_DISPLAY_REMOVE_SYSTEM_DECORATIONS, displayId, 0) + .sendToTarget(); + } + } + // This was previously called from WM, but is now called from WMShell public void onRecentsAnimationStateChanged(boolean running) { synchronized (mLock) { @@ -1510,6 +1532,15 @@ public class CommandQueue extends IStatusBar.Stub implements mHandler.obtainMessage(MSG_ENTER_DESKTOP, args).sendToTarget(); } + @Override + public void setHasNavigationBar(int displayId, boolean hasNavigationBar) { + synchronized (mLock) { + mHandler.obtainMessage(MSG_SET_HAS_NAVIGATION_BAR, displayId, + hasNavigationBar ? 1 : 0).sendToTarget(); + } + } + + private final class H extends Handler { private H(Looper l) { super(l); @@ -1825,6 +1856,11 @@ public class CommandQueue extends IStatusBar.Stub implements mCallbacks.get(i).onDisplayReady(msg.arg1); } break; + case MSG_DISPLAY_REMOVE_SYSTEM_DECORATIONS: + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).onDisplayRemoveSystemDecorations(msg.arg1); + } + break; case MSG_RECENTS_ANIMATION_STATE_CHANGED: for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).onRecentsAnimationStateChanged(msg.arg1 > 0); @@ -2036,6 +2072,11 @@ public class CommandQueue extends IStatusBar.Stub implements } break; } + case MSG_SET_HAS_NAVIGATION_BAR: + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).setHasNavigationBar(msg.arg1, msg.arg2 != 0); + } + break; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 10b726b90894..c8f972774ab0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -121,7 +121,6 @@ public class NotificationLockscreenUserManagerImpl implements private static final long LOCK_TIME_FOR_SENSITIVE_REDACTION_MS = TimeUnit.MINUTES.toMillis(10); - private final Lazy<NotificationVisibilityProvider> mVisibilityProviderLazy; private final Lazy<CommonNotifCollection> mCommonNotifCollectionLazy; private final DevicePolicyManager mDevicePolicyManager; @@ -751,7 +750,7 @@ public class NotificationLockscreenUserManagerImpl implements } long lastLockedTime = mLastLockTime.get(); - if (ent.getSbn().getPostTime() < lastLockedTime) { + if (ent.getSbn().getNotification().getWhen() < lastLockedTime) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt index 6ce3228531d2..a682f9674e2e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt @@ -30,6 +30,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -47,6 +48,7 @@ import com.android.systemui.res.R import com.android.systemui.statusbar.chips.ui.compose.modifiers.neverDecreaseWidth import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel +import com.android.systemui.statusbar.chips.ui.viewmodel.rememberChronometerState @Composable fun OngoingActivityChip(model: OngoingActivityChipModel.Shown, modifier: Modifier = Modifier) { @@ -195,11 +197,12 @@ private fun ChipContent(viewModel: OngoingActivityChipModel.Shown, modifier: Mod val context = LocalContext.current when (viewModel) { is OngoingActivityChipModel.Shown.Timer -> { - ChronometerText( - startTimeMillis = viewModel.startTimeMs, + val timerState = rememberChronometerState(startTimeMillis = viewModel.startTimeMs) + Text( + text = timerState.currentTimeText, style = MaterialTheme.typography.labelLarge, color = Color(viewModel.colors.text(context)), - modifier = modifier, + modifier = modifier.neverDecreaseWidth(), ) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChronometerText.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChronometerState.kt index 1c14d3349027..62789782d0a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChronometerText.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/ChronometerState.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 The Android Open Source Project + * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.statusbar.chips.ui.compose +package com.android.systemui.statusbar.chips.ui.viewmodel import android.os.SystemClock import android.text.format.DateUtils.formatElapsedTime -import androidx.compose.material3.LocalTextStyle -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -26,13 +24,9 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableLongStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.TextStyle import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.repeatOnLifecycle -import com.android.systemui.statusbar.chips.ui.compose.modifiers.neverDecreaseWidth import kotlinx.coroutines.delay /** Platform-optimized interface for getting current time */ @@ -59,7 +53,10 @@ class ChronometerState(private val timeSource: TimeSource, private val startTime /** Remember and manage the ChronometerState */ @Composable -fun rememberChronometerState(timeSource: TimeSource, startTimeMillis: Long): ChronometerState { +fun rememberChronometerState( + startTimeMillis: Long, + timeSource: TimeSource = remember { TimeSource { SystemClock.elapsedRealtime() } }, +): ChronometerState { val state = remember(timeSource, startTimeMillis) { ChronometerState(timeSource, startTimeMillis) } val lifecycleOwner = LocalLifecycleOwner.current @@ -69,25 +66,3 @@ fun rememberChronometerState(timeSource: TimeSource, startTimeMillis: Long): Chr return state } - -/** - * A composable chronometer that displays elapsed time with constrained width. The width of the text - * is only allowed to increase. This ensures there is no visual jitter when individual digits in the - * text change due to the timer ticking. - */ -@Composable -fun ChronometerText( - startTimeMillis: Long, - modifier: Modifier = Modifier, - color: Color = Color.Unspecified, - style: TextStyle = LocalTextStyle.current, - timeSource: TimeSource = remember { TimeSource { SystemClock.elapsedRealtime() } }, -) { - val state = rememberChronometerState(timeSource, startTimeMillis) - Text( - text = state.currentTimeText, - style = style, - color = color, - modifier = modifier.neverDecreaseWidth(), - ) -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt index 629cb831f17a..a0e44bfd7620 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt @@ -24,7 +24,7 @@ import com.android.systemui.flags.RefactorFlagUtils @Suppress("NOTHING_TO_INLINE") object StabilizeHeadsUpGroup { /** The aconfig flag name */ - const val FLAG_NAME: String = Flags.FLAG_STABILIZE_HEADS_UP_GROUP + const val FLAG_NAME: String = Flags.FLAG_STABILIZE_HEADS_UP_GROUP_V2 /** A token used for dependency declaration */ val token: FlagToken @@ -33,7 +33,7 @@ object StabilizeHeadsUpGroup { /** Is the refactor enabled */ @JvmStatic inline val isEnabled - get() = Flags.stabilizeHeadsUpGroup() + get() = Flags.stabilizeHeadsUpGroupV2() /** * Called to ensure code is only run when the flag is enabled. This protects users from the diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationStackModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationStackModule.kt new file mode 100644 index 000000000000..6ceeb6aae7a5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationStackModule.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.dagger + +import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHider +import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHiderImpl +import dagger.Binds +import dagger.BindsOptionalOf +import dagger.Module + +/** + * This is meant to be bound in SystemUI variants with [NotificationStackScrollLayoutController]. + */ +@Module +interface NotificationStackGoogleModule { + @Binds + fun bindNotificationStackRebindingHider( + impl: NotificationStackRebindingHiderImpl + ): NotificationStackRebindingHider +} + +/** This is meant to be used by all SystemUI variants, also those without NSSL. */ +@Module +interface NotificationStackModule { + @BindsOptionalOf + fun bindOptionalOfNotificationStackRebindingHider(): NotificationStackRebindingHider +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 086c32cbae5d..0346108856a2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -117,6 +117,7 @@ import javax.inject.Provider; NotificationMemoryModule.class, NotificationStatsLoggerModule.class, NotificationsLogModule.class, + NotificationStackModule.class, }) public interface NotificationsModule { @Binds diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt new file mode 100644 index 000000000000..664b2afe90b4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.promoted + +import android.app.Flags +import android.view.LayoutInflater +import android.view.View +import android.view.View.GONE +import android.view.View.VISIBLE +import android.view.ViewStub +import android.widget.Chronometer +import android.widget.DateTimeView +import android.widget.ImageView +import android.widget.ProgressBar +import android.widget.TextView +import androidx.compose.runtime.Composable +import androidx.compose.runtime.key +import androidx.compose.ui.viewinterop.AndroidView +import androidx.core.view.isVisible +import com.android.internal.R +import com.android.internal.widget.BigPictureNotificationImageView +import com.android.internal.widget.CachingIconView +import com.android.internal.widget.ImageFloatingTextView +import com.android.internal.widget.NotificationExpandButton +import com.android.internal.widget.NotificationProgressBar +import com.android.internal.widget.NotificationRowIconView +import com.android.systemui.lifecycle.rememberViewModel +import com.android.systemui.res.R as systemuiR +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.When +import com.android.systemui.statusbar.notification.promoted.ui.viewmodel.AODPromotedNotificationViewModel + +@Composable +fun AODPromotedNotification(viewModelFactory: AODPromotedNotificationViewModel.Factory) { + if (!PromotedNotificationUiAod.isEnabled) { + return + } + + val viewModel = + rememberViewModel(traceName = "AODPromotedNotification") { viewModelFactory.create() } + + val content = viewModel.content ?: return + + key(content.identity) { + AndroidView( + factory = { context -> + LayoutInflater.from(context) + .inflate(content.layoutResource, /* root= */ null) + .apply { setTag(viewUpdaterTagId, AODPromotedNotificationViewUpdater(this)) } + }, + update = { view -> + (view.getTag(viewUpdaterTagId) as AODPromotedNotificationViewUpdater).update( + content + ) + }, + ) + } +} + +private val PromotedNotificationContentModel.layoutResource: Int + get() { + return if (Flags.notificationsRedesignTemplates()) { + when (style) { + Style.BigPicture -> R.layout.notification_2025_template_expanded_big_picture + Style.BigText -> R.layout.notification_2025_template_expanded_big_text + Style.Call -> R.layout.notification_2025_template_expanded_call + Style.Progress -> R.layout.notification_2025_template_expanded_progress + Style.Ineligible -> 0 + } + } else { + when (style) { + Style.BigPicture -> R.layout.notification_template_material_big_picture + Style.BigText -> R.layout.notification_template_material_big_text + Style.Call -> R.layout.notification_template_material_big_call + Style.Progress -> R.layout.notification_template_material_progress + Style.Ineligible -> 0 + } + } + } + +private class AODPromotedNotificationViewUpdater(root: View) { + private val alertedIcon: View? = root.findViewById(R.id.alerted_icon) + private val alternateExpandTarget: View? = root.findViewById(R.id.alternate_expand_target) + private val appNameDivider: View? = root.findViewById(R.id.app_name_divider) + private val appNameText: TextView? = root.findViewById(R.id.app_name_text) + private val bigPicture: BigPictureNotificationImageView? = root.findViewById(R.id.big_picture) + private val bigText: ImageFloatingTextView? = root.findViewById(R.id.big_text) + private var chronometerStub: ViewStub? = root.findViewById(R.id.chronometer) + private var chronometer: Chronometer? = null + private val closeButton: View? = root.findViewById(R.id.close_button) + private val conversationText: TextView? = root.findViewById(R.id.conversation_text) + private val expandButton: NotificationExpandButton? = root.findViewById(R.id.expand_button) + private val headerText: TextView? = root.findViewById(R.id.header_text) + private val headerTextDivider: View? = root.findViewById(R.id.header_text_divider) + private val headerTextSecondary: TextView? = root.findViewById(R.id.header_text_secondary) + private val headerTextSecondaryDivider: View? = + root.findViewById(R.id.header_text_secondary_divider) + private val icon: NotificationRowIconView? = root.findViewById(R.id.icon) + private val leftIcon: ImageView? = root.findViewById(R.id.left_icon) + private val notificationProgressEndIcon: CachingIconView? = + root.findViewById(R.id.notification_progress_end_icon) + private val notificationProgressStartIcon: CachingIconView? = + root.findViewById(R.id.notification_progress_start_icon) + private val profileBadge: ImageView? = root.findViewById(R.id.profile_badge) + private val text: ImageFloatingTextView? = root.findViewById(R.id.text) + private val time: DateTimeView? = root.findViewById(R.id.time) + private val timeDivider: View? = root.findViewById(R.id.time_divider) + private val title: TextView? = root.findViewById(R.id.title) + private val verificationDivider: View? = root.findViewById(R.id.verification_divider) + private val verificationIcon: ImageView? = root.findViewById(R.id.verification_icon) + private val verificationText: TextView? = root.findViewById(R.id.verification_text) + + private var oldProgressStub = root.findViewById<View>(R.id.progress) as? ViewStub + private var oldProgress: ProgressBar? = null + private val newProgress = root.findViewById<View>(R.id.progress) as? NotificationProgressBar + + fun update(content: PromotedNotificationContentModel) { + when (content.style) { + Style.BigPicture -> updateBigPicture(content) + Style.BigText -> updateBigText(content) + Style.Call -> updateCall(content) + Style.Progress -> updateProgress(content) + Style.Ineligible -> {} + } + } + + private fun updateBigPicture(content: PromotedNotificationContentModel) { + updateHeader(content) + + updateTitle(title, content) + updateText(text, content) + + bigPicture?.visibility = GONE + } + + private fun updateBigText(content: PromotedNotificationContentModel) { + updateHeader(content) + + updateTitle(title, content) + updateText(bigText, content) + } + + private fun updateCall(content: PromotedNotificationContentModel) { + updateConversationHeader(content) + + updateText(text, content) + } + + private fun updateProgress(content: PromotedNotificationContentModel) { + updateHeader(content) + + updateTitle(title, content) + updateText(text, content) + + updateNewProgressBar(content) + } + + private fun updateNewProgressBar(content: PromotedNotificationContentModel) { + notificationProgressStartIcon?.visibility = GONE + notificationProgressEndIcon?.visibility = GONE + content.progress?.let { + newProgress?.setProgressModel(it.toBundle()) + newProgress?.visibility = VISIBLE + } ?: run { newProgress?.visibility = GONE } + } + + private fun updateHeader(content: PromotedNotificationContentModel) { + updateAppName(content) + updateTextView(headerTextSecondary, content.subText) + updateTitle(headerText, content) + updateTimeAndChronometer(content) + + updateHeaderDividers(content) + + leftIcon?.visibility = GONE + alternateExpandTarget?.visibility = GONE + expandButton?.visibility = GONE + closeButton?.visibility = GONE + } + + private fun updateHeaderDividers(content: PromotedNotificationContentModel) { + val hasAppName = content.appName != null && content.appName.isNotEmpty() + val hasSubText = content.subText != null && content.subText.isNotEmpty() + val hasHeader = content.title != null && content.title.isNotEmpty() + val hasTimeOrChronometer = content.time != null + + val hasTextBeforeSubText = hasAppName + val hasTextBeforeHeader = hasAppName || hasSubText + val hasTextBeforeTime = hasAppName || hasSubText || hasHeader + + val showDividerBeforeSubText = hasTextBeforeSubText && hasSubText + val showDividerBeforeHeader = hasTextBeforeHeader && hasHeader + val showDividerBeforeTime = hasTextBeforeTime && hasTimeOrChronometer + + headerTextSecondaryDivider?.isVisible = showDividerBeforeSubText + headerTextDivider?.isVisible = showDividerBeforeHeader + timeDivider?.isVisible = showDividerBeforeTime + } + + private fun updateConversationHeader(content: PromotedNotificationContentModel) { + updateTitle(conversationText, content) + updateAppName(content) + updateTimeAndChronometer(content) + + updateConversationHeaderDividers(content) + + updateTextView(verificationText, content.verificationText) + } + + private fun updateConversationHeaderDividers(content: PromotedNotificationContentModel) { + val hasTitle = content.title != null + val hasAppName = content.appName != null + val hasTimeOrChronometer = content.time != null + val hasVerification = content.verificationIcon != null || content.verificationText != null + + val hasTextBeforeAppName = hasTitle + val hasTextBeforeTime = hasTitle || hasAppName + val hasTextBeforeVerification = hasTitle || hasAppName || hasTimeOrChronometer + + val showDividerBeforeAppName = hasTextBeforeAppName && hasAppName + val showDividerBeforeTime = hasTextBeforeTime && hasTimeOrChronometer + val showDividerBeforeVerification = hasTextBeforeVerification && hasVerification + + appNameDivider?.isVisible = showDividerBeforeAppName + timeDivider?.isVisible = showDividerBeforeTime + verificationDivider?.isVisible = showDividerBeforeVerification + } + + private fun updateAppName(content: PromotedNotificationContentModel) { + updateTextView(appNameText, content.appName) + } + + private fun updateTitle(titleView: TextView?, content: PromotedNotificationContentModel) { + updateTextView(titleView, content.title, color = Color.PrimaryText) + } + + private fun updateTimeAndChronometer(content: PromotedNotificationContentModel) { + setTextViewColor(time, Color.SecondaryText) + setTextViewColor(chronometer, Color.SecondaryText) + + val timeValue = content.time + + if (timeValue == null) { + time?.visibility = GONE + chronometer?.visibility = GONE + } else if (timeValue.mode == When.Mode.BasicTime) { + time?.visibility = VISIBLE + time?.setTime(timeValue.time) + chronometer?.visibility = GONE + } else { + inflateChronometer() + + time?.visibility = GONE + chronometer?.visibility = VISIBLE + chronometer?.base = timeValue.time + chronometer?.isCountDown = (timeValue.mode == When.Mode.CountDown) + chronometer?.setStarted(true) + } + } + + private fun inflateChronometer() { + if (chronometer != null) { + return + } + + chronometer = chronometerStub?.inflate() as Chronometer + chronometerStub = null + } + + private fun updateText( + view: ImageFloatingTextView?, + content: PromotedNotificationContentModel, + ) { + view?.setHasImage(false) + updateTextView(view, content.text) + } + + private fun updateTextView( + view: TextView?, + text: CharSequence?, + color: Color = Color.SecondaryText, + ) { + setTextViewColor(view, color) + + if (text != null && text.isNotEmpty()) { + view?.text = text + view?.visibility = VISIBLE + } else { + view?.text = "" + view?.visibility = GONE + } + } + + private fun setTextViewColor(view: TextView?, color: Color) { + view?.setTextColor(color.color.toInt()) + } + + private enum class Color(val color: UInt) { + Background(0x00000000u), + PrimaryText(0xFFFFFFFFu), + SecondaryText(0xFFCCCCCCu), + } +} + +private val viewUpdaterTagId = systemuiR.id.aod_promoted_notification_view_updater_tag diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLogger.kt index a43f8dbc1b5d..4ccdc65ba91a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLogger.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.promoted +import androidx.constraintlayout.widget.ConstraintSet import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.LogLevel.ERROR import com.android.systemui.log.core.LogLevel.INFO @@ -65,6 +66,58 @@ constructor(@PromotedNotificationLog private val buffer: LogBuffer) { { "extraction succeeded: $str2 for $str1" }, ) } + + fun logBinderBindSkipped(reason: String) { + buffer.log( + AOD_VIEW_BINDER_TAG, + INFO, + { str1 = reason }, + { "binder skipped binding: $str1" }, + ) + } + + fun logBinderAttached() { + buffer.log(AOD_VIEW_BINDER_TAG, INFO, "binder attached") + } + + fun logBinderDetached() { + buffer.log(AOD_VIEW_BINDER_TAG, INFO, "binder detached") + } + + fun logBinderBoundNotification() { + buffer.log(AOD_VIEW_BINDER_TAG, INFO, "binder bound notification") + } + + fun logBinderUnboundNotification() { + buffer.log(AOD_VIEW_BINDER_TAG, INFO, "binder unbound notification") + } + + fun logSectionAddedViews() { + buffer.log(AOD_SECTION_TAG, INFO, "section added views") + } + + fun logSectionBoundData() { + buffer.log(AOD_SECTION_TAG, INFO, "section bound data") + } + + fun logSectionAppliedConstraints() { + buffer.log(AOD_SECTION_TAG, INFO, "section applied constraints") + } + + fun logSectionRemovedViews() { + buffer.log(AOD_SECTION_TAG, INFO, "section removed views") + } } private const val EXTRACTION_TAG = "PromotedNotificationContentExtractor" +private const val AOD_VIEW_BINDER_TAG = "AODPromotedNotificationViewBinder" +private const val AOD_SECTION_TAG = "AodPromotedNotificationSection" + +private fun visibilityToString(visibility: Int): String { + return when (visibility) { + ConstraintSet.VISIBLE -> "VISIBLE" + ConstraintSet.INVISIBLE -> "INVISIBLE" + ConstraintSet.GONE -> "GONE" + else -> "UNKNOWN($visibility)" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ui/viewmodel/AODPromotedNotificationViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ui/viewmodel/AODPromotedNotificationViewModel.kt index adfa6a10814d..3bbd217dcab4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ui/viewmodel/AODPromotedNotificationViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/ui/viewmodel/AODPromotedNotificationViewModel.kt @@ -16,31 +16,32 @@ package com.android.systemui.statusbar.notification.promoted.ui.viewmodel -import com.android.systemui.dagger.SysUISingleton +import androidx.compose.runtime.getValue +import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.lifecycle.Hydrator import com.android.systemui.statusbar.notification.promoted.domain.interactor.AODPromotedNotificationInteractor import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel -import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Identity -import javax.inject.Inject -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.map +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject -@SysUISingleton class AODPromotedNotificationViewModel -@Inject -constructor(interactor: AODPromotedNotificationInteractor) { - private val content: Flow<PromotedNotificationContentModel?> = interactor.content - private val identity: Flow<Identity?> = content.mapNonNullsKeepingNulls { it.identity } +@AssistedInject +constructor(interactor: AODPromotedNotificationInteractor) : ExclusiveActivatable() { + private val hydrator = Hydrator("AODPromotedNotificationViewModel.hydrator") - val notification: Flow<PromotedNotificationViewModel?> = - identity.distinctUntilChanged().mapNonNullsKeepingNulls { identity -> - val updates = interactor.content.filterNotNull().filter { it.identity == identity } - PromotedNotificationViewModel(identity, updates) - } -} + val content: PromotedNotificationContentModel? by + hydrator.hydratedStateOf( + traceName = "content", + initialValue = null, + source = interactor.content, + ) + + override suspend fun onActivated(): Nothing { + hydrator.activate() + } -private fun <T, R> Flow<T?>.mapNonNullsKeepingNulls(block: (T) -> R): Flow<R?> = map { - it?.let(block) + @AssistedFactory + interface Factory { + fun create(): AODPromotedNotificationViewModel + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 598ff09ba3b0..ee8f9eabb9a0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -21,6 +21,7 @@ import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_ import static android.service.notification.NotificationListenerService.REASON_CANCEL; import static com.android.systemui.flags.Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE; +import static com.android.systemui.Flags.notificationsPinnedHunInShade; import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP; import static com.android.systemui.statusbar.policy.RemoteInputView.FOCUS_ANIMATION_MIN_SCALE; @@ -252,6 +253,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private NotificationGuts mGuts; private NotificationEntry mEntry; private String mAppName; + private NotificationRebindingTracker mRebindingTracker; private FalsingManager mFalsingManager; /** @@ -1526,7 +1528,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // TODO: Move content inflation logic out of this call RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry); params.setNeedsReinflation(true); - mRowContentBindStage.requestRebind(mEntry, null /* callback */); + + var rebindEndCallback = mRebindingTracker.trackRebinding(mEntry.getKey()); + mRowContentBindStage.requestRebind(mEntry, (e) -> rebindEndCallback.onFinished()); Trace.endSection(); } @@ -2015,9 +2019,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView SmartReplyConstants smartReplyConstants, SmartReplyController smartReplyController, IStatusBarService statusBarService, - UiEventLogger uiEventLogger) { + UiEventLogger uiEventLogger, + NotificationRebindingTracker notificationRebindingTracker) { mEntry = entry; mAppName = appName; + mRebindingTracker = notificationRebindingTracker; if (mMenuRow == null) { mMenuRow = new NotificationMenuRow(mContext, peopleNotificationIdentifier); } @@ -3179,7 +3185,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @Override public boolean mustStayOnScreen() { - return mIsHeadsUp && mMustStayOnScreen; + // Must stay on screen in the open shade regardless how much the stack is scrolled if: + // 1. Is HUN and not marked as seen yet (isHeadsUp && mustStayOnScreen) + // 2. Is an FSI HUN (isPinned) + return mIsHeadsUp && mMustStayOnScreen || notificationsPinnedHunInShade() && isPinned(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java index e06280e36bc8..626230353bd7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java @@ -106,6 +106,7 @@ public class ExpandableNotificationRowController implements NotifViewController private final NotificationGutsManager mNotificationGutsManager; private final OnUserInteractionCallback mOnUserInteractionCallback; private final FalsingManager mFalsingManager; + private final NotificationRebindingTracker mNotificationRebindingTracker; private final FeatureFlagsClassic mFeatureFlags; private final boolean mAllowLongPress; private final PeopleNotificationIdentifier mPeopleNotificationIdentifier; @@ -275,7 +276,8 @@ public class ExpandableNotificationRowController implements NotifViewController NotificationDismissibilityProvider dismissibilityProvider, IStatusBarService statusBarService, UiEventLogger uiEventLogger, - MSDLPlayer msdlPlayer) { + MSDLPlayer msdlPlayer, + NotificationRebindingTracker notificationRebindingTracker) { mView = view; mListContainer = listContainer; mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory; @@ -295,6 +297,7 @@ public class ExpandableNotificationRowController implements NotifViewController mNotificationGutsManager = notificationGutsManager; mOnUserInteractionCallback = onUserInteractionCallback; mFalsingManager = falsingManager; + mNotificationRebindingTracker = notificationRebindingTracker; mOnFeedbackClickListener = mNotificationGutsManager::openGuts; mAllowLongPress = allowLongPress; mFeatureFlags = featureFlags; @@ -343,7 +346,8 @@ public class ExpandableNotificationRowController implements NotifViewController mSmartReplyConstants, mSmartReplyController, mStatusBarService, - mUiEventLogger + mUiEventLogger, + mNotificationRebindingTracker ); mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); if (mAllowLongPress) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRebindingTracker.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRebindingTracker.kt new file mode 100644 index 000000000000..40dbdf27c920 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRebindingTracker.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.row + +import com.android.app.tracing.FlowTracing.traceEach +import com.android.app.tracing.TraceUtils.traceAsyncClosable +import com.android.app.tracing.TrackGroupUtils.trackGroup +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +/** + * Tracks notification rebindings in progress as a result of a configuration change (such as density + * or font size) + */ +@SysUISingleton +class NotificationRebindingTracker +@Inject +constructor( + activeNotificationsInteractor: ActiveNotificationsInteractor, + @Background private val bgScope: CoroutineScope, + @Application private val appScope: CoroutineScope, +) : CoreStartable { + + private val rebindingKeys = MutableStateFlow(emptySet<String>()) + private val activeKeys: Flow<Set<String>> = + activeNotificationsInteractor.allRepresentativeNotifications + .map { notifications: Map<String, *> -> + notifications.map { (notifKey, _) -> notifKey }.toSet() + } + .traceEach(trackGroup("shade", "activeKeys")) + + /** + * Emits the current number of active notification rebinding in progress. + * + * Note the usaged of the [appScope] instead of the bg one is intentional, as we need the value + * immediately also in the same frame if it changes. + */ + val rebindingInProgressCount: StateFlow<Int> = + rebindingKeys + .map { it.size } + .traceEach(trackGroup("shade", "rebindingInProgressCount"), traceEmissionCount = true) + .stateIn(appScope, started = SharingStarted.Eagerly, initialValue = 0) + + override fun start() { + syncRebindingKeysWithActiveKeys() + } + + private fun syncRebindingKeysWithActiveKeys() { + // Let's make sure that the "rebindingKeys" set doesn't contain entries that are not active + // anymore. + bgScope.launch { + activeKeys.collect { activeKeys -> + rebindingKeys.update { currentlyBeingInflated -> + currentlyBeingInflated.intersect(activeKeys) + } + } + } + } + + /** Should be called when the inflation begins */ + fun trackRebinding(key: String): RebindFinishedCallback { + val endTrace = + traceAsyncClosable( + trackGroupName = "Notifications", + trackName = "Rebinding", + sliceName = "Rebinding in progress for $key", + ) + rebindingKeys.value += key + return RebindFinishedCallback { + endTrace() + rebindingKeys.value -= key + } + } + + /** + * Callback to notify the end of a rebiding. Views are expected to be in the hierarchy when this + * is called. + */ + fun interface RebindFinishedCallback { + fun onFinished() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt index 49e38def98a6..0b299d965b09 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt @@ -799,6 +799,7 @@ constructor( } redacted.setLargeIcon(original.getLargeIcon()) redacted.setSmallIcon(original.smallIcon) + redacted.setWhen(original.getWhen()) return redacted } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackRebindingHider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackRebindingHider.kt new file mode 100644 index 000000000000..dba2308ea34b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackRebindingHider.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.stack + +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +/** + * Allows to hide the content of the notification stack during notification rebinding. + * + * Note that this is mainly created to allow SystemUI variants without NSSL to provide their own + * implementations. + */ +interface NotificationStackRebindingHider { + /** Sets the Notification stack visibility. */ + fun setVisible(visible: Boolean, animated: Boolean) +} + +@SysUISingleton +class NotificationStackRebindingHiderImpl +@Inject +constructor(private val nsslController: NotificationStackScrollLayoutController) : + NotificationStackRebindingHider { + override fun setVisible(visible: Boolean, animated: Boolean) { + nsslController.updateContainerVisibilityForRebind(visible, animated) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index f57107141f61..bf24c873c693 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -21,6 +21,7 @@ import static android.os.Trace.TRACE_TAG_APP; import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_UP; +import static com.android.app.tracing.TrackGroupUtils.trackGroup; import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING; import static com.android.internal.jank.InteractionJankMonitor.CUJ_SHADE_CLEAR_ALL; import static com.android.systemui.Flags.notificationOverExpansionClippingFix; @@ -1395,6 +1396,16 @@ public class NotificationStackScrollLayout } } + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + if (Trace.isEnabled()) { + Trace.setCounter( + trackGroup(/* groupName= */ "shade", /* trackName= */ "NSSLResultingAlpha"), + (int) (alpha * 100)); + } + } + private boolean isCurrentlyAnimating() { return mStateAnimator.isRunning(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index dc0fae80d041..8eaef3681e5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -249,9 +249,26 @@ public class NotificationStackScrollLayoutController implements Dumpable { } }; + private static final Property<NotificationStackScrollLayoutController, Float> + HIDE_DURING_REBINDING_PROPERTY = new Property<>(Float.class, + "HideNotificationsAlphaDuringRebind") { + @Override + public Float get(NotificationStackScrollLayoutController object) { + return object.mMaxAlphaForRebind; + } + + @Override + public void set(NotificationStackScrollLayoutController object, Float value) { + object.setMaxAlphaForRebind(value); + } + }; + @Nullable private ObjectAnimator mHideAlphaAnimator = null; + @Nullable + private ObjectAnimator mRebindAlphaAnimator = null; + private final Runnable mSensitiveStateChangedListener = new Runnable() { @Override public void run() { @@ -295,6 +312,7 @@ public class NotificationStackScrollLayoutController implements Dumpable { private float mMaxAlphaForKeyguard = 1.0f; private String mMaxAlphaForKeyguardSource = "constructor"; private float mMaxAlphaForUnhide = 1.0f; + private float mMaxAlphaForRebind = 1.0f; private float mMaxAlphaFromView = 1.0f; /** @@ -1244,6 +1262,16 @@ public class NotificationStackScrollLayoutController implements Dumpable { } /** + * Max alpha for rebind. + * + * Used to hide notifications while rebiding is in progress (e.g. after a density change). + */ + public void setMaxAlphaForRebind(float alpha) { + mMaxAlphaForRebind = alpha; + updateAlpha(); + } + + /** * Applies a blur effect to the view. * * @param blurRadius Radius of blur @@ -1261,8 +1289,10 @@ public class NotificationStackScrollLayoutController implements Dumpable { private void updateAlpha() { if (mView != null) { - mView.setAlpha(Math.min(Math.min(mMaxAlphaFromView, mMaxAlphaForKeyguard), - Math.min(mMaxAlphaForUnhide, mMaxAlphaForGlanceableHub))); + float newAlpha = Math.min(mMaxAlphaForRebind, + Math.min(Math.min(mMaxAlphaFromView, mMaxAlphaForKeyguard), + Math.min(mMaxAlphaForUnhide, mMaxAlphaForGlanceableHub))); + mView.setAlpha(newAlpha); } } @@ -1289,6 +1319,26 @@ public class NotificationStackScrollLayoutController implements Dumpable { } } + /** + * Sets whether the nssl should be visible or not. Used during notification rebinding, to hide + * possible flickers that happen when display density changes. (e.g. as a result of the shade + * moving to a different display.) + */ + public void updateContainerVisibilityForRebind(boolean visible, boolean animate) { + if (mRebindAlphaAnimator != null) { + mRebindAlphaAnimator.cancel(); + } + + final float targetAlpha = visible ? 1f : 0f; + + if (animate) { + mRebindAlphaAnimator = createAlphaAnimatorForRebind(targetAlpha); + mRebindAlphaAnimator.start(); + } else { + HIDE_DURING_REBINDING_PROPERTY.set(this, targetAlpha); + } + } + private ObjectAnimator createAlphaAnimator(float targetAlpha) { final ObjectAnimator objectAnimator = ObjectAnimator .ofFloat(this, HIDE_ALPHA_PROPERTY, targetAlpha); @@ -1297,6 +1347,14 @@ public class NotificationStackScrollLayoutController implements Dumpable { return objectAnimator; } + private ObjectAnimator createAlphaAnimatorForRebind(float targetAlpha) { + final ObjectAnimator objectAnimator = ObjectAnimator + .ofFloat(this, HIDE_DURING_REBINDING_PROPERTY, targetAlpha); + objectAnimator.setInterpolator(STANDARD); + objectAnimator.setDuration(ANIMATION_DURATION_STANDARD); + return objectAnimator; + } + public float calculateAppearFraction(float height) { SceneContainerFlag.assertInLegacyMode(); return mView.calculateAppearFraction(height); @@ -1688,6 +1746,7 @@ public class NotificationStackScrollLayoutController implements Dumpable { public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { pw.println("mMaxAlphaFromView=" + mMaxAlphaFromView); pw.println("mMaxAlphaForUnhide=" + mMaxAlphaForUnhide); + pw.println("mMaxAlphaForRebind=" + mMaxAlphaForRebind); pw.println("mMaxAlphaForGlanceableHub=" + mMaxAlphaForGlanceableHub); pw.println("mMaxAlphaForKeyguard=" + mMaxAlphaForKeyguard); pw.println("mMaxAlphaForKeyguardSource=" + mMaxAlphaForKeyguardSource); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt index 705845ff984c..5d8f06ff51be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/SharedNotificationContainer.kt @@ -60,6 +60,7 @@ class SharedNotificationContainer(context: Context, attrs: AttributeSet?) : marginTop: Int, marginEnd: Int, marginBottom: Int, + nsslAlpha: Float, ) { val constraintSet = ConstraintSet() constraintSet.clone(baseConstraintSet) @@ -83,6 +84,10 @@ class SharedNotificationContainer(context: Context, attrs: AttributeSet?) : } } + // Constraint layout sets the alpha to 1 if it's not set explicitly in the constraint + // set. Let's keep the current nssl alpha instead, otherwise this might interfere with + // animations. + setAlpha(nsslId, nsslAlpha) connect(nsslId, START, startConstraintId, START, marginStart) if ( !SceneContainerFlag.isEnabled || diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt index 3ea4d488357d..1965b9538df0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt @@ -76,6 +76,7 @@ constructor( marginTop = it.marginTop, marginEnd = it.marginEnd, marginBottom = it.marginBottom, + nsslAlpha = controller.alpha, ) controller.setOverExpansion(0f) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index 1a97ab635028..4825a10e901b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -144,6 +144,7 @@ public class NotificationIconContainer extends ViewGroup { private int mMaxIcons = Integer.MAX_VALUE; private boolean mOverrideIconColor; + private boolean mUseInverseOverrideIconColor; private boolean mIsStaticLayout = true; private final HashMap<View, IconState> mIconStates = new HashMap<>(); private int mDotPadding; @@ -169,6 +170,7 @@ public class NotificationIconContainer extends ViewGroup { private final int[] mAbsolutePosition = new int[2]; @Nullable private View mIsolatedIconForAnimation; private int mThemedTextColorPrimary; + private int mThemedTextColorPrimaryInverse; @Nullable private Runnable mIsolatedIconAnimationEndRunnable; private boolean mUseIncreasedIconScale; @@ -191,6 +193,8 @@ public class NotificationIconContainer extends ViewGroup { com.android.internal.R.style.Theme_DeviceDefault_DayNight); mThemedTextColorPrimary = Utils.getColorAttr(themedContext, com.android.internal.R.attr.textColorPrimary).getDefaultColor(); + mThemedTextColorPrimaryInverse = Utils.getColorAttr(themedContext, + com.android.internal.R.attr.textColorPrimaryInverse).getDefaultColor(); } @Override @@ -713,6 +717,10 @@ public class NotificationIconContainer extends ViewGroup { mOverrideIconColor = override; } + public void setUseInverseOverrideIconColor(boolean override) { + mUseInverseOverrideIconColor = override; + } + public class IconState extends ViewState { public float iconAppearAmount = 1.0f; public float clampedAppearAmount = 1.0f; @@ -821,7 +829,9 @@ public class NotificationIconContainer extends ViewGroup { } icon.setVisibleState(visibleState, animationsAllowed); if (mOverrideIconColor) { - icon.setIconColor(mThemedTextColorPrimary, + int overrideIconColor = mUseInverseOverrideIconColor + ? mThemedTextColorPrimaryInverse : mThemedTextColorPrimary; + icon.setIconColor(overrideIconColor, /* animate= */ needsCannedAnimation && animationsAllowed); } if (animate) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 2cd8eafcdb54..0f6c3069609e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -868,6 +868,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump * bounds instead. */ public void setClipsQsScrim(boolean clipScrim) { + if (Flags.notificationShadeBlur()) { + // Never clip scrims when blur is enabled, colors of UI elements are supposed to "add" + // up across the scrims. + mClipsQsScrim = false; + return; + } if (clipScrim == mClipsQsScrim) { return; } @@ -957,11 +963,20 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mBehindAlpha = 1; mNotificationsAlpha = behindFraction * mDefaultScrimAlpha; } else { - mBehindAlpha = mLargeScreenShadeInterpolator.getBehindScrimAlpha( - mPanelExpansionFraction * mDefaultScrimAlpha); - mNotificationsAlpha = - mLargeScreenShadeInterpolator.getNotificationScrimAlpha( - mPanelExpansionFraction); + if (Flags.notificationShadeBlur()) { + // TODO (b/390730594): match any spec for controlling alpha based on shade + // expansion fraction. + mBehindAlpha = mState.getBehindAlpha() * mPanelExpansionFraction; + mBehindTint = mState.getBehindTint(); + mNotificationsAlpha = mState.getNotifAlpha() * mPanelExpansionFraction; + mNotificationsTint = mState.getNotifTint(); + } else { + mBehindAlpha = mLargeScreenShadeInterpolator.getBehindScrimAlpha( + mPanelExpansionFraction * mDefaultScrimAlpha); + mNotificationsAlpha = + mLargeScreenShadeInterpolator.getNotificationScrimAlpha( + mPanelExpansionFraction); + } } mBehindTint = mState.getBehindTint(); mInFrontAlpha = 0; @@ -1015,7 +1030,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump .saturate(mTransitionToLockScreenFullShadeNotificationsProgress); } else if (mState == ScrimState.SHADE_LOCKED) { // going from KEYGUARD to SHADE_LOCKED state - mNotificationsAlpha = getInterpolatedFraction(); + if (Flags.notificationShadeBlur()) { + mNotificationsAlpha = mState.getNotifAlpha() * getInterpolatedFraction(); + } else { + mNotificationsAlpha = getInterpolatedFraction(); + } } else if (mState == ScrimState.GLANCEABLE_HUB && mTransitionToFullShadeProgress == 0.0f) { // Notification scrim should not be visible on the glanceable hub unless the diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index 14937295051d..8170e6d91a0f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -26,6 +26,7 @@ import com.android.systemui.Flags; import com.android.systemui.dock.DockManager; import com.android.systemui.res.R; import com.android.systemui.scrim.ScrimView; +import com.android.systemui.shade.ui.ShadeColors; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import kotlinx.coroutines.ExperimentalCoroutinesApi; @@ -86,16 +87,24 @@ public enum ScrimState { } else { mAnimationDuration = ScrimController.ANIMATION_DURATION; } - mFrontTint = mBackgroundColor; - mBehindTint = mBackgroundColor; - mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT; - - mFrontAlpha = 0; - mBehindAlpha = mClipQsScrim ? 1 : mScrimBehindAlphaKeyguard; - mNotifAlpha = mClipQsScrim ? mScrimBehindAlphaKeyguard : 0; - if (mClipQsScrim) { - updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor); + if (Flags.notificationShadeBlur()) { + mBehindTint = Color.TRANSPARENT; + mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources()); + mBehindAlpha = 0.0f; + mNotifAlpha = 0.0f; + mFrontAlpha = 0.0f; + } else { + mFrontTint = mBackgroundColor; + mBehindTint = mBackgroundColor; + mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT; + mFrontAlpha = 0; + mBehindAlpha = mClipQsScrim ? 1 : mScrimBehindAlphaKeyguard; + mNotifAlpha = mClipQsScrim ? mScrimBehindAlphaKeyguard : 0; + if (mClipQsScrim) { + updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor); + } } + } }, @@ -169,13 +178,21 @@ public enum ScrimState { @Override public void prepare(ScrimState previousState) { - mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha; - mNotifAlpha = 1f; - mFrontAlpha = 0f; - mBehindTint = mClipQsScrim ? Color.TRANSPARENT : mBackgroundColor; + if (Flags.notificationShadeBlur()) { + mBehindTint = ShadeColors.shadePanel(mScrimBehind.getResources()); + mBehindAlpha = Color.alpha(mBehindTint) / 255.0f; + mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources()); + mNotifAlpha = Color.alpha(mNotifTint) / 255.0f; + mFrontAlpha = 0.0f; + } else { + mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha; + mNotifAlpha = 1f; + mFrontAlpha = 0f; + mBehindTint = mClipQsScrim ? Color.TRANSPARENT : mBackgroundColor; - if (mClipQsScrim) { - updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor); + if (mClipQsScrim) { + updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor); + } } } }, @@ -282,6 +299,13 @@ public enum ScrimState { mFrontTint = mBackgroundColor; mBehindTint = mBackgroundColor; mBlankScreen = true; + } else if (Flags.notificationShadeBlur()) { + mBehindTint = ShadeColors.shadePanel(mScrimBehind.getResources()); + mBehindAlpha = Color.alpha(mBehindTint) / 255.0f; + mNotifTint = ShadeColors.notificationScrim(mScrimBehind.getResources()); + mNotifAlpha = Color.alpha(mNotifTint) / 255.0f; + mFrontAlpha = 0.0f; + return; } if (mClipQsScrim) { diff --git a/packages/SystemUI/src/com/android/systemui/utils/SafeIconLoader.kt b/packages/SystemUI/src/com/android/systemui/utils/SafeIconLoader.kt new file mode 100644 index 000000000000..41bef7f94fa2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/utils/SafeIconLoader.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.utils + +import android.app.IUriGrantsManager +import android.content.Context +import android.graphics.drawable.Drawable +import android.graphics.drawable.Icon +import android.os.UserHandle +import com.android.systemui.dagger.qualifiers.Application +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +/** + * Use to load an icon (from another app) safely. It will prevent cross user icon loading if there + * are no permissions. + */ +class SafeIconLoader +@AssistedInject +constructor( + @Assisted("serviceUid") private val serviceUid: Int, + @Assisted private val packageName: String, + @Assisted("userId") private val userId: Int, + @Application private val applicationContext: Context, + private val iUriGrantsManager: IUriGrantsManager, +) { + + private val serviceContext = + applicationContext.createPackageContextAsUser(packageName, 0, UserHandle.of(userId)) + + /** + * Tries to load the icon. If it fails in any way (for example, cross user permissions), it will + * return `null`. Prefer calling this in a background thread. + */ + fun load(icon: Icon): Drawable? { + return icon.loadDrawableCheckingUriGrant( + serviceContext, + iUriGrantsManager, + serviceUid, + packageName, + ) + } + + @AssistedFactory + interface Factory { + + fun create( + @Assisted("serviceUid") serviceUid: Int, + packageName: String, + @Assisted("userId") userId: Int, + ): SafeIconLoader + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteria.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteria.kt new file mode 100644 index 000000000000..bee45645bfdb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteria.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2025 The Android Open 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.volume.panel.component.mediaoutput.domain + +import android.content.Context +import com.android.settingslib.media.PhoneMediaDevice.isDesktop +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope +import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.stateIn + +@VolumePanelScope +class MediaOutputAvailabilityCriteria +@Inject +constructor( + @Application private val context: Context, + @VolumePanelScope private val scope: CoroutineScope, +) : ComponentAvailabilityCriteria { + + private val availability = + flow { emit(!isDesktop(context)) }.stateIn(scope, SharingStarted.WhileSubscribed(), false) + + override fun isAvailable(): Flow<Boolean> = availability +} diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt index 9055d18a9f55..8487ee751948 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt @@ -23,6 +23,7 @@ import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.flowOf /** * A no-op implementation of [WallpaperRepository]. @@ -33,6 +34,6 @@ import kotlinx.coroutines.flow.asStateFlow @SysUISingleton class NoopWallpaperRepository @Inject constructor() : WallpaperRepository { override val wallpaperInfo: StateFlow<WallpaperInfo?> = MutableStateFlow(null).asStateFlow() - override val wallpaperSupportsAmbientMode = MutableStateFlow(false).asStateFlow() + override val wallpaperSupportsAmbientMode = flowOf(false) override var rootView: View? = null } diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt index 015b480eddc8..ed43f8323c31 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt @@ -25,6 +25,8 @@ import android.os.Bundle import android.os.UserHandle import android.view.View import androidx.annotation.VisibleForTesting +import com.android.app.tracing.coroutines.launchTraced as launch +import com.android.internal.R import com.android.systemui.Flags import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton @@ -47,10 +49,10 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn -import com.android.app.tracing.coroutines.launchTraced as launch import kotlinx.coroutines.withContext /** A repository storing information about the current wallpaper. */ @@ -59,7 +61,7 @@ interface WallpaperRepository { val wallpaperInfo: StateFlow<WallpaperInfo?> /** Emits true if the current user's current wallpaper supports ambient mode. */ - val wallpaperSupportsAmbientMode: StateFlow<Boolean> + val wallpaperSupportsAmbientMode: Flow<Boolean> /** Set rootView to get its windowToken afterwards */ var rootView: View? @@ -78,9 +80,6 @@ constructor( private val wallpaperManager: WallpaperManager, context: Context, ) : WallpaperRepository { - private val deviceSupportsAodWallpaper = - context.resources.getBoolean(com.android.internal.R.bool.config_dozeSupportsAodWallpaper) - private val wallpaperChanged: Flow<Unit> = broadcastDispatcher .broadcastFlow(IntentFilter(Intent.ACTION_WALLPAPER_CHANGED), user = UserHandle.ALL) @@ -121,7 +120,7 @@ constructor( ) override val wallpaperInfo: StateFlow<WallpaperInfo?> = - if (!wallpaperManager.isWallpaperSupported || !deviceSupportsAodWallpaper) { + if (!wallpaperManager.isWallpaperSupported) { MutableStateFlow(null).asStateFlow() } else { combine(wallpaperChanged, selectedUser, ::Pair) @@ -136,25 +135,8 @@ constructor( ) } - override val wallpaperSupportsAmbientMode: StateFlow<Boolean> = - wallpaperInfo - .map { - if (ambientAod()) { - // Force this mode for now, until ImageWallpaper supports it directly - // TODO(b/371236225) - true - } else { - // If WallpaperInfo is null, it's ImageWallpaper which never supports ambient - // mode. - it?.supportsAmbientMode() == true - } - } - .stateIn( - scope, - // Always be listening for wallpaper changes. - SharingStarted.Eagerly, - initialValue = if (ambientAod()) true else false, - ) + override val wallpaperSupportsAmbientMode: Flow<Boolean> = + flowOf(context.resources.getBoolean(R.bool.config_dozeSupportsAodWallpaper) && ambientAod()) override var rootView: View? = null diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt index 88795cada716..1b15832d4913 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt @@ -18,9 +18,9 @@ package com.android.systemui.wallpapers.domain.interactor import com.android.systemui.wallpapers.data.repository.WallpaperRepository import javax.inject.Inject -import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.Flow class WallpaperInteractor @Inject constructor(val wallpaperRepository: WallpaperRepository) { - val wallpaperSupportsAmbientMode: StateFlow<Boolean> = + val wallpaperSupportsAmbientMode: Flow<Boolean> = wallpaperRepository.wallpaperSupportsAmbientMode } diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperViewModel.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperViewModel.kt index a51acf66432a..197f2b010a97 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperViewModel.kt @@ -18,8 +18,8 @@ package com.android.systemui.wallpapers.ui.viewmodel import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor import javax.inject.Inject -import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.Flow class WallpaperViewModel @Inject constructor(interactor: WallpaperInteractor) { - val wallpaperSupportsAmbientMode: StateFlow<Boolean> = interactor.wallpaperSupportsAmbientMode + val wallpaperSupportsAmbientMode: Flow<Boolean> = interactor.wallpaperSupportsAmbientMode } diff --git a/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt b/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt index fee32b5e7e78..8e0616c00196 100644 --- a/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt @@ -17,13 +17,23 @@ package com.android.systemui.window.domain.interactor import android.util.Log +import com.android.systemui.Flags import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER import com.android.systemui.window.data.repository.WindowRootViewBlurRepository import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn /** * Interactor that provides the blur state for the window root view @@ -33,9 +43,21 @@ import kotlinx.coroutines.flow.asStateFlow class WindowRootViewBlurInteractor @Inject constructor( + @Application private val applicationScope: CoroutineScope, private val keyguardInteractor: KeyguardInteractor, + keyguardTransitionInteractor: KeyguardTransitionInteractor, private val repository: WindowRootViewBlurRepository, ) { + private var isBouncerTransitionInProgress: StateFlow<Boolean> = + if (Flags.bouncerUiRevamp()) { + keyguardTransitionInteractor + .transitionValue(PRIMARY_BOUNCER) + .map { it > 0f } + .distinctUntilChanged() + .stateIn(applicationScope, SharingStarted.Eagerly, false) + } else { + MutableStateFlow(false) + } /** * Invoked by the view after blur of [appliedBlurRadius] was successfully applied on the window @@ -57,8 +79,7 @@ constructor( val onBlurAppliedEvent: Flow<Int> = repository.onBlurApplied /** - * Request to apply blur while on bouncer, this takes precedence over other blurs (from - * shade). + * Request to apply blur while on bouncer, this takes precedence over other blurs (from shade). */ fun requestBlurForBouncer(blurRadius: Int) { repository.isBlurOpaque.value = false @@ -76,7 +97,10 @@ constructor( * @return whether the request for blur was processed or not. */ fun requestBlurForShade(blurRadius: Int, opaque: Boolean): Boolean { - if (keyguardInteractor.primaryBouncerShowing.value) { + // We need to check either of these because they are two different sources of truth, + // primaryBouncerShowing changes early to true/false, but blur is + // coordinated by transition value. + if (keyguardInteractor.primaryBouncerShowing.value || isBouncerTransitionInProgress.value) { return false } Log.d(TAG, "requestingBlurForShade for $blurRadius $opaque") diff --git a/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt index d2069cfdfdc6..dbccc1d8cca4 100644 --- a/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt @@ -49,7 +49,6 @@ object WindowRootViewBinder { view.repeatWhenAttached { Log.d(TAG, "Binding root view") var frameCallbackPendingExecution: FrameCallback? = null - val viewRootImpl = view.rootView.viewRootImpl view.viewModel( minWindowLifecycleState = WindowLifecycleState.ATTACHED, factory = { viewModelFactory.create() }, @@ -64,13 +63,13 @@ object WindowRootViewBinder { val newFrameCallback = FrameCallback { frameCallbackPendingExecution = null blurUtils.applyBlur( - viewRootImpl, + view.rootView?.viewRootImpl, blurState.radius, blurState.isOpaque, ) viewModel.onBlurApplied(blurState.radius) } - blurUtils.prepareBlur(viewRootImpl, blurState.radius) + blurUtils.prepareBlur(view.rootView?.viewRootImpl, blurState.radius) if (frameCallbackPendingExecution != null) { choreographer.removeFrameCallback(frameCallbackPendingExecution) } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index 1729a4dfa945..bac2c47f51c7 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -55,7 +55,6 @@ import com.android.systemui.plugins.clocks.ClockTickRate import com.android.systemui.plugins.clocks.ThemeConfig import com.android.systemui.plugins.clocks.ZenData import com.android.systemui.plugins.clocks.ZenData.ZenMode -import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.res.R import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.policy.BatteryController @@ -132,7 +131,6 @@ class ClockEventControllerTest : SysuiTestCase() { @Mock private lateinit var parentView: View @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock private lateinit var userTracker: UserTracker - @Mock private lateinit var powerInteractor: PowerInteractor @Mock private lateinit var zenModeController: ZenModeController private var zenModeControllerCallback: ZenModeController.Callback? = null @@ -180,7 +178,6 @@ class ClockEventControllerTest : SysuiTestCase() { zenModeController, zenModeInteractor, userTracker, - powerInteractor, ) underTest.clock = clock diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 2645811fa4ad..312d2ffd74e4 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -38,6 +38,7 @@ import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELL import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_STOPPED; import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT; import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT; +import static com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2; import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED; import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN; @@ -139,6 +140,7 @@ import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider; import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor; import com.android.systemui.deviceentry.data.repository.FaceWakeUpTriggersConfig; import com.android.systemui.deviceentry.data.repository.FaceWakeUpTriggersConfigImpl; import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor; @@ -180,6 +182,9 @@ import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -189,9 +194,6 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import platform.test.runner.parameterized.ParameterizedAndroidJunit4; -import platform.test.runner.parameterized.Parameters; - @SmallTest @RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper @@ -304,6 +306,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { private JavaAdapter mJavaAdapter; @Mock private SceneInteractor mSceneInteractor; + @Mock + private CommunalSceneInteractor mCommunalSceneInteractor; @Captor private ArgumentCaptor<FaceAuthenticationListener> mFaceAuthenticationListener; @@ -1084,6 +1088,49 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + public void udfpsStopsListeningWhenCommunalShowing() { + // GIVEN keyguard showing + mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); + mKeyguardUpdateMonitor.setKeyguardShowing(true, false); + + assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isTrue(); + + // WHEN communal is shown + mKeyguardUpdateMonitor.onCommunalShowingChanged(true); + + // THEN shouldn't listen for fingerprint + assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isFalse(); + + // WHEN alternate bouncer shows on top of communal, we should listen for fingerprint + mKeyguardUpdateMonitor.setAlternateBouncerVisibility(true); + assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isTrue(); + + // WHEN communal is hidden + mKeyguardUpdateMonitor.onCommunalShowingChanged(false); + mKeyguardUpdateMonitor.setAlternateBouncerVisibility(false); + + // THEN listen for fingerprint + assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isTrue(); + } + + @Test + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + public void sfpsNotAffectedByCommunalShowing() { + // GIVEN keyguard showing + mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); + mKeyguardUpdateMonitor.setKeyguardShowing(true, false); + + assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isTrue(); + + // WHEN communal is shown + mKeyguardUpdateMonitor.onCommunalShowingChanged(true); + + // THEN we should still listen for fingerprint if not UDFPS + assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isTrue(); + } + + @Test public void testFingerprintPowerPressed_restartsFingerprintListeningStateWithDelay() { mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback .onAuthenticationError(FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED, ""); @@ -2669,7 +2716,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mTaskStackChangeListeners, mSelectedUserInteractor, mActivityTaskManager, () -> mAlternateBouncerInteractor, () -> mJavaAdapter, - () -> mSceneInteractor); + () -> mSceneInteractor, + mCommunalSceneInteractor); setAlternateBouncerVisibility(false); setPrimaryBouncerVisibility(false); setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker); diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt index 39e1e1d8bb57..b1d0f86c364c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt @@ -2,6 +2,9 @@ package com.android.systemui.controls.management import android.content.ComponentName import android.content.Intent +import android.content.pm.ApplicationInfo +import android.content.pm.ServiceInfo +import android.graphics.drawable.Drawable import android.os.Bundle import android.testing.TestableLooper import android.view.View @@ -11,25 +14,31 @@ import android.window.OnBackInvokedDispatcher import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.rule.ActivityTestRule -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.activity.SingleActivityFactory +import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.CustomIconCache import com.android.systemui.controls.controller.ControlsControllerImpl +import com.android.systemui.res.R import com.android.systemui.settings.UserTracker import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.utils.SafeIconLoader import com.google.common.truth.Truth.assertThat import java.util.concurrent.CountDownLatch import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Answers import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.eq import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.mock import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @@ -41,6 +50,7 @@ class ControlsEditingActivityTest : SysuiTestCase() { val TEST_COMPONENT = ComponentName("TestPackageName", "TestClassName") val TEST_STRUCTURE: CharSequence = "TestStructure" val TEST_APP: CharSequence = "TestApp" + val TEST_UID = 12345 } private val uiExecutor = FakeExecutor(FakeSystemClock()) @@ -51,6 +61,10 @@ class ControlsEditingActivityTest : SysuiTestCase() { @Mock lateinit var customIconCache: CustomIconCache + @Mock lateinit var controlsListingController: ControlsListingController + + @Mock(answer = Answers.RETURNS_MOCKS) lateinit var safeIconLoaderFactory: SafeIconLoader.Factory + private var latch: CountDownLatch = CountDownLatch(1) @Mock private lateinit var mockDispatcher: OnBackInvokedDispatcher @@ -66,8 +80,10 @@ class ControlsEditingActivityTest : SysuiTestCase() { controller, userTracker, customIconCache, + controlsListingController, + safeIconLoaderFactory, mockDispatcher, - latch + latch, ) }, /* initialTouchMode= */ false, @@ -77,6 +93,9 @@ class ControlsEditingActivityTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) + + val serviceInfo = ControlsServiceInfo(TEST_COMPONENT, "", TEST_UID) + `when`(controlsListingController.getCurrentServices()).thenReturn(listOf(serviceInfo)) } @Test @@ -86,7 +105,7 @@ class ControlsEditingActivityTest : SysuiTestCase() { verify(mockDispatcher) .registerOnBackInvokedCallback( eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), - captureCallback.capture() + captureCallback.capture(), ) activityRule.finishActivity() latch.await() // ensure activity is finished @@ -158,19 +177,40 @@ class ControlsEditingActivityTest : SysuiTestCase() { } ) + private fun ControlsServiceInfo( + componentName: ComponentName, + label: CharSequence, + uid: Int, + ): ControlsServiceInfo { + val serviceInfo = + ServiceInfo().apply { + applicationInfo = ApplicationInfo().apply { this.uid = uid } + packageName = componentName.packageName + name = componentName.className + } + return Mockito.spy(ControlsServiceInfo(mContext, serviceInfo)).apply { + Mockito.doReturn(label).`when`(this).loadLabel() + Mockito.doReturn(mock(Drawable::class.java)).`when`(this).loadIcon() + } + } + class TestableControlsEditingActivity( executor: FakeExecutor, controller: ControlsControllerImpl, userTracker: UserTracker, customIconCache: CustomIconCache, + controlsListingController: ControlsListingController, + safeIconLoaderFactory: SafeIconLoader.Factory, private val mockDispatcher: OnBackInvokedDispatcher, - private val latch: CountDownLatch + private val latch: CountDownLatch, ) : ControlsEditingActivity( executor, controller, userTracker, customIconCache, + controlsListingController, + safeIconLoaderFactory, ) { var startActivityData: StartActivityData? = null diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt index 7fb74b3439bc..5eb93721e735 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt @@ -2,6 +2,9 @@ package com.android.systemui.controls.management import android.content.ComponentName import android.content.Intent +import android.content.pm.ApplicationInfo +import android.content.pm.ServiceInfo +import android.graphics.drawable.Drawable import android.os.Bundle import android.service.controls.Control import android.testing.TestableLooper @@ -13,19 +16,21 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.FlakyTest import androidx.test.filters.SmallTest import androidx.test.rule.ActivityTestRule -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.activity.SingleActivityFactory import com.android.systemui.controls.ControlStatus +import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.controller.ControlsControllerImpl import com.android.systemui.controls.controller.createLoadDataObject import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.res.R import com.android.systemui.settings.UserTracker import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.whenever +import com.android.systemui.utils.SafeIconLoader import com.google.common.truth.Truth.assertThat import com.google.common.util.concurrent.MoreExecutors import java.util.concurrent.CountDownLatch @@ -39,6 +44,7 @@ import org.mockito.Answers import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.eq import org.mockito.Mockito.mock import org.mockito.Mockito.verify @@ -57,6 +63,7 @@ class ControlsFavoritingActivityTest : SysuiTestCase() { whenever(structure).thenReturn(TEST_STRUCTURE) } val TEST_APP: CharSequence = "TestApp" + val TEST_UID = 12345 private fun View.waitForPost() { val latch = CountDownLatch(1) @@ -72,6 +79,10 @@ class ControlsFavoritingActivityTest : SysuiTestCase() { @Mock lateinit var userTracker: UserTracker + @Mock lateinit var controlsListingController: ControlsListingController + + @Mock(answer = Answers.RETURNS_MOCKS) lateinit var safeIconLoaderFactory: SafeIconLoader.Factory + private var latch: CountDownLatch = CountDownLatch(1) @Mock private lateinit var mockDispatcher: OnBackInvokedDispatcher @@ -88,8 +99,10 @@ class ControlsFavoritingActivityTest : SysuiTestCase() { executor, controller, userTracker, + controlsListingController, + safeIconLoaderFactory, mockDispatcher, - latch + latch, ) }, /* initialTouchMode= */ false, @@ -99,6 +112,10 @@ class ControlsFavoritingActivityTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) + + val serviceInfo = ControlsServiceInfo(TEST_COMPONENT, "", TEST_UID) + Mockito.`when`(controlsListingController.getCurrentServices()) + .thenReturn(listOf(serviceInfo)) } // b/259549854 to root-cause and fix @@ -110,7 +127,7 @@ class ControlsFavoritingActivityTest : SysuiTestCase() { verify(mockDispatcher) .registerOnBackInvokedCallback( eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), - captureCallback.capture() + captureCallback.capture(), ) activityRule.finishActivity() latch.await() // ensure activity is finished @@ -178,17 +195,38 @@ class ControlsFavoritingActivityTest : SysuiTestCase() { } ) + private fun ControlsServiceInfo( + componentName: ComponentName, + label: CharSequence, + uid: Int, + ): ControlsServiceInfo { + val serviceInfo = + ServiceInfo().apply { + applicationInfo = ApplicationInfo().apply { this.uid = uid } + packageName = componentName.packageName + name = componentName.className + } + return Mockito.spy(ControlsServiceInfo(mContext, serviceInfo)).apply { + Mockito.doReturn(label).`when`(this).loadLabel() + Mockito.doReturn(mock(Drawable::class.java)).`when`(this).loadIcon() + } + } + class TestableControlsFavoritingActivity( executor: Executor, controller: ControlsControllerImpl, userTracker: UserTracker, + controlsListingController: ControlsListingController, + safeIconLoaderFactory: SafeIconLoader.Factory, private val mockDispatcher: OnBackInvokedDispatcher, - private val latch: CountDownLatch + private val latch: CountDownLatch, ) : ControlsFavoritingActivity( executor, controller, userTracker, + safeIconLoaderFactory, + controlsListingController, ) { var triedToFinish = false diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt index 4b30fa5dd161..c1c90bd41fea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt @@ -21,6 +21,7 @@ import android.content.ComponentName import android.content.res.ColorStateList import android.graphics.drawable.GradientDrawable import android.graphics.drawable.Icon +import android.graphics.drawable.ShapeDrawable import android.service.controls.Control import android.service.controls.DeviceTypes import android.service.controls.templates.ControlTemplate @@ -30,18 +31,21 @@ import android.view.View import android.view.ViewGroup import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.controls.ControlsMetricsLogger import com.android.systemui.controls.controller.ControlInfo import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.res.R import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.utils.SafeIconLoader import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock +import org.mockito.Mockito.`when` @SmallTest @RunWith(AndroidJUnit4::class) @@ -52,14 +56,20 @@ class ControlViewHolderTest : SysuiTestCase() { private lateinit var cvh: ControlViewHolder private lateinit var baseLayout: ViewGroup + private lateinit var safeIconLoader: SafeIconLoader @Before fun setUp() { TestableLooper.get(this).runWithLooper { - baseLayout = LayoutInflater.from(mContext).inflate( - R.layout.controls_base_item, null, false) as ViewGroup + baseLayout = + LayoutInflater.from(mContext).inflate(R.layout.controls_base_item, null, false) + as ViewGroup - cvh = ControlViewHolder( + safeIconLoader = mock(SafeIconLoader::class.java) + `when`(safeIconLoader.load(any())).thenReturn(PLAIN_DRAWABLE) + + cvh = + ControlViewHolder( baseLayout, mock(ControlsController::class.java), FakeExecutor(clock), @@ -68,15 +78,20 @@ class ControlViewHolderTest : SysuiTestCase() { mock(ControlsMetricsLogger::class.java), uid = 100, 0, - ) + safeIconLoader, + ) - val cws = ControlWithState( + val cws = + ControlWithState( ComponentName.createRelative("pkg", "cls"), ControlInfo( - CONTROL_ID, CONTROL_TITLE, "subtitle", DeviceTypes.TYPE_AIR_FRESHENER + CONTROL_ID, + CONTROL_TITLE, + "subtitle", + DeviceTypes.TYPE_AIR_FRESHENER, ), - Control.StatelessBuilder(CONTROL_ID, mock(PendingIntent::class.java)).build() - ) + Control.StatelessBuilder(CONTROL_ID, mock(PendingIntent::class.java)).build(), + ) cvh.bindData(cws, isLocked = false) } @@ -84,10 +99,11 @@ class ControlViewHolderTest : SysuiTestCase() { @Test fun updateStatusRow_customIconWithTint_iconTintRemains() { - val control = Control.StatelessBuilder(DEFAULT_CONTROL) + val control = + Control.StatelessBuilder(DEFAULT_CONTROL) .setCustomIcon( - Icon.createWithResource(mContext.resources, R.drawable.ic_emergency_star) - .setTint(TINT_COLOR) + Icon.createWithResource(mContext.resources, R.drawable.ic_emergency_star) + .setTint(TINT_COLOR) ) .build() @@ -99,10 +115,11 @@ class ControlViewHolderTest : SysuiTestCase() { @Test fun updateStatusRow_customIconWithTintList_iconTintListRemains() { val customIconTintList = ColorStateList.valueOf(TINT_COLOR) - val control = Control.StatelessBuilder(CONTROL_ID, mock(PendingIntent::class.java)) + val control = + Control.StatelessBuilder(CONTROL_ID, mock(PendingIntent::class.java)) .setCustomIcon( - Icon.createWithResource(mContext.resources, R.drawable.ic_emergency_star) - .setTintList(customIconTintList) + Icon.createWithResource(mContext.resources, R.drawable.ic_emergency_star) + .setTintList(customIconTintList) ) .build() @@ -113,22 +130,54 @@ class ControlViewHolderTest : SysuiTestCase() { @Test fun chevronIcon() { - val control = Control.StatefulBuilder(CONTROL_ID, mock(PendingIntent::class.java)) - .setStatus(Control.STATUS_OK) - .setControlTemplate(ControlTemplate.NO_TEMPLATE) - .build() - val cws = ControlWithState( - ComponentName.createRelative("pkg", "cls"), - ControlInfo( - CONTROL_ID, CONTROL_TITLE, "subtitle", DeviceTypes.TYPE_AIR_FRESHENER - ), - control - ) + val control = + Control.StatefulBuilder(CONTROL_ID, mock(PendingIntent::class.java)) + .setStatus(Control.STATUS_OK) + .setControlTemplate(ControlTemplate.NO_TEMPLATE) + .build() + val cws = + ControlWithState( + ComponentName.createRelative("pkg", "cls"), + ControlInfo(CONTROL_ID, CONTROL_TITLE, "subtitle", DeviceTypes.TYPE_AIR_FRESHENER), + control, + ) cvh.bindData(cws, false) val chevronIcon = baseLayout.requireViewById<View>(R.id.chevron_icon) assertThat(chevronIcon.visibility).isEqualTo(View.VISIBLE) } + + @Test + fun drawableLoadedSafely_showsPlainDrawableLoaded() { + val control = + Control.StatelessBuilder(DEFAULT_CONTROL) + .setCustomIcon( + Icon.createWithResource(mContext.resources, R.drawable.ic_emergency_star) + .setTint(TINT_COLOR) + ) + .build() + + cvh.updateStatusRow(enabled = true, CONTROL_TITLE, DRAWABLE, COLOR, control) + + assertThat(cvh.icon.drawable).isSameInstanceAs(PLAIN_DRAWABLE) + } + + @Test + fun drawableNotLoadedSafely_showsDefaultDrawable() { + `when`(safeIconLoader.load(any())).thenReturn(null) + + val control = + Control.StatelessBuilder(DEFAULT_CONTROL) + .setCustomIcon( + Icon.createWithResource(mContext.resources, R.drawable.ic_emergency_star) + .setTint(TINT_COLOR) + ) + .build() + + cvh.updateStatusRow(enabled = true, CONTROL_TITLE, DRAWABLE, COLOR, control) + + assertThat(cvh.icon.drawable).isSameInstanceAs(DRAWABLE) + } } private const val CONTROL_ID = "CONTROL_ID" @@ -136,6 +185,7 @@ private const val CONTROL_TITLE = "CONTROL_TITLE" private const val TINT_COLOR = 0x00ff00 // Should be different from [COLOR] private val DRAWABLE = GradientDrawable() +private val PLAIN_DRAWABLE = ShapeDrawable() private val COLOR = ColorStateList.valueOf(0xffff00) -private val DEFAULT_CONTROL = Control.StatelessBuilder( - CONTROL_ID, mock(PendingIntent::class.java)).build() +private val DEFAULT_CONTROL = + Control.StatelessBuilder(CONTROL_ID, mock(PendingIntent::class.java)).build() diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt index 20890a7780c8..3a0bda4b3259 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt @@ -63,6 +63,7 @@ import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.utils.SafeIconLoader import com.android.wm.shell.taskview.TaskView import com.android.wm.shell.taskview.TaskViewFactory import com.google.common.truth.Truth.assertThat @@ -71,6 +72,7 @@ import java.util.function.Consumer 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.clearInvocations import org.mockito.Mockito.doAnswer @@ -102,6 +104,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { @Mock lateinit var featureFlags: FeatureFlags @Mock lateinit var packageManager: PackageManager @Mock lateinit var systemUIDialogFactory: SystemUIDialog.Factory + @Mock(answer = Answers.RETURNS_MOCKS) lateinit var safeIconLoaderFactory: SafeIconLoader.Factory private val preferredPanelRepository = kosmos.selectedComponentRepository private lateinit var fakeDialogController: FakeSystemUIDialogController @@ -130,7 +133,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { Context.LAYOUT_INFLATER_SERVICE, mContext.baseContext .getSystemService(LayoutInflater::class.java)!! - .cloneInContext(mContext) + .cloneInContext(mContext), ) parent = FrameLayout(mContext) @@ -154,6 +157,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { authorizedPanelsRepository, preferredPanelRepository, featureFlags, + safeIconLoaderFactory, ControlsDialogsFactory(systemUIDialogFactory), dumpManager, ) @@ -303,7 +307,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { assertThat( intent.getBooleanExtra( ControlsProviderService.EXTRA_LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, - false + false, ) ) .isTrue() @@ -341,7 +345,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { assertThat( intent.getBooleanExtra( ControlsProviderService.EXTRA_LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, - false + false, ) ) .isTrue() @@ -374,7 +378,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { assertThat( pendingIntent.intent.getBooleanExtra( ControlsProviderService.EXTRA_LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, - false + false, ) ) .isTrue() @@ -393,7 +397,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { assertThat( newPendingIntent.intent.getBooleanExtra( ControlsProviderService.EXTRA_LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, - false + false, ) ) .isFalse() @@ -416,9 +420,9 @@ class ControlsUiControllerImplTest : SysuiTestCase() { StructureInfo( checkNotNull(ComponentName.unflattenFromString("pkg/.cls1")), "a", - ArrayList() + ArrayList(), ) - ), + ) ) preferredPanelRepository.setSelectedComponent( SelectedComponentRepository.SelectedComponent(selectedItems[0]) @@ -598,7 +602,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { private fun ControlsServiceInfo( componentName: ComponentName, label: CharSequence, - panelComponentName: ComponentName? = null + panelComponentName: ComponentName? = null, ): ControlsServiceInfo { val serviceInfo = ServiceInfo().apply { @@ -621,7 +625,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { view: View?, name: String, context: Context, - attrs: AttributeSet + attrs: AttributeSet, ): View? { return onCreateView(name, context, attrs) } @@ -629,7 +633,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { override fun onCreateView( name: String, context: Context, - attrs: AttributeSet + attrs: AttributeSet, ): View? { if (FrameLayout::class.java.simpleName.equals(name)) { val mock: FrameLayout = mock { diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt index 909680866d20..4e1ccfb07220 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt @@ -21,14 +21,11 @@ import android.content.Context import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.os.PowerManager -import android.os.Process -import android.os.UserHandle import android.os.UserManager import android.testing.TestableContext import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.dx.mockito.inline.extended.ExtendedMockito import com.android.internal.app.AssistUtils import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase @@ -42,6 +39,7 @@ import com.android.systemui.model.SysUiState import com.android.systemui.model.sceneContainerPlugin import com.android.systemui.navigationbar.NavigationBarController import com.android.systemui.navigationbar.NavigationModeController +import com.android.systemui.process.ProcessWrapper import com.android.systemui.recents.OverviewProxyService.ACTION_QUICKSTEP import com.android.systemui.settings.FakeDisplayTracker import com.android.systemui.settings.UserTracker @@ -92,6 +90,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { private val kosmos = testKosmos() private lateinit var subject: OverviewProxyService @Mock private val dumpManager = DumpManager() + @Mock private val processWrapper = ProcessWrapper() private val displayTracker = FakeDisplayTracker(mContext) private val fakeSystemClock = FakeSystemClock() private val sysUiState = SysUiState(displayTracker, kosmos.sceneContainerPlugin) @@ -146,6 +145,8 @@ class OverviewProxyServiceTest : SysuiTestCase() { mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) + // return isSystemUser as true by default. + `when`(processWrapper.isSystemUser).thenReturn(true) subject = createOverviewProxyService(context) } @@ -202,68 +203,44 @@ class OverviewProxyServiceTest : SysuiTestCase() { @Test fun connectToOverviewService_primaryUserNoVisibleBgUsersSupported_expectBindService() { - val mockitoSession = - ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking() - try { - `when`(Process.myUserHandle()).thenReturn(UserHandle.SYSTEM) - `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false) - val spyContext = spy(context) - val ops = createOverviewProxyService(spyContext) - ops.startConnectionToCurrentUser() - verify(spyContext, atLeast(1)).bindServiceAsUser(any(), any(), anyInt(), any()) - } finally { - mockitoSession.finishMocking() - } + `when`(processWrapper.isSystemUser).thenReturn(true) + `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false) + val spyContext = spy(context) + val ops = createOverviewProxyService(spyContext) + ops.startConnectionToCurrentUser() + verify(spyContext, atLeast(1)).bindServiceAsUser(any(), any(), anyInt(), any()) } @Test fun connectToOverviewService_nonPrimaryUserNoVisibleBgUsersSupported_expectNoBindService() { - val mockitoSession = - ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking() - try { - `when`(Process.myUserHandle()).thenReturn(UserHandle.of(12345)) - `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false) - val spyContext = spy(context) - val ops = createOverviewProxyService(spyContext) - ops.startConnectionToCurrentUser() - verify(spyContext, times(0)).bindServiceAsUser(any(), any(), anyInt(), any()) - } finally { - mockitoSession.finishMocking() - } + `when`(processWrapper.isSystemUser).thenReturn(false) + `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false) + val spyContext = spy(context) + val ops = createOverviewProxyService(spyContext) + ops.startConnectionToCurrentUser() + verify(spyContext, times(0)).bindServiceAsUser(any(), any(), anyInt(), any()) } @Test fun connectToOverviewService_nonPrimaryBgUserVisibleBgUsersSupported_expectBindService() { - val mockitoSession = - ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking() - try { - `when`(Process.myUserHandle()).thenReturn(UserHandle.of(12345)) - `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true) - `when`(userManager.isUserForeground()).thenReturn(false) - val spyContext = spy(context) - val ops = createOverviewProxyService(spyContext) - ops.startConnectionToCurrentUser() - verify(spyContext, atLeast(1)).bindServiceAsUser(any(), any(), anyInt(), any()) - } finally { - mockitoSession.finishMocking() - } + `when`(processWrapper.isSystemUser).thenReturn(false) + `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true) + `when`(userManager.isUserForeground()).thenReturn(false) + val spyContext = spy(context) + val ops = createOverviewProxyService(spyContext) + ops.startConnectionToCurrentUser() + verify(spyContext, atLeast(1)).bindServiceAsUser(any(), any(), anyInt(), any()) } @Test fun connectToOverviewService_nonPrimaryFgUserVisibleBgUsersSupported_expectNoBindService() { - val mockitoSession = - ExtendedMockito.mockitoSession().spyStatic(Process::class.java).startMocking() - try { - `when`(Process.myUserHandle()).thenReturn(UserHandle.of(12345)) - `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true) - `when`(userManager.isUserForeground()).thenReturn(true) - val spyContext = spy(context) - val ops = createOverviewProxyService(spyContext) - ops.startConnectionToCurrentUser() - verify(spyContext, times(0)).bindServiceAsUser(any(), any(), anyInt(), any()) - } finally { - mockitoSession.finishMocking() - } + `when`(processWrapper.isSystemUser).thenReturn(false) + `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(true) + `when`(userManager.isUserForeground()).thenReturn(true) + val spyContext = spy(context) + val ops = createOverviewProxyService(spyContext) + ops.startConnectionToCurrentUser() + verify(spyContext, times(0)).bindServiceAsUser(any(), any(), anyInt(), any()) } private fun createOverviewProxyService(ctx: Context): OverviewProxyService { @@ -292,6 +269,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { unfoldTransitionProgressForwarder, broadcastDispatcher, backAnimation, + processWrapper, ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index 5aee92939ed5..ce5058095562 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -941,6 +941,57 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { assertThat(row.getImageResolver().getContext()).isSameInstanceAs(userContext); } + @Test + @EnableFlags(com.android.systemui.Flags.FLAG_NOTIFICATIONS_PINNED_HUN_IN_SHADE) + public void mustStayOnScreen_false() throws Exception { + final ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + assertThat(row.mustStayOnScreen()).isFalse(); + } + + @Test + @EnableFlags(com.android.systemui.Flags.FLAG_NOTIFICATIONS_PINNED_HUN_IN_SHADE) + public void mustStayOnScreen_isHeadsUp_markedAsSeen() throws Exception { + final ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + // When the row is a HUN + row.setHeadsUp(true); + //Then it must stay on screen + assertThat(row.mustStayOnScreen()).isTrue(); + // And when the user has seen it + row.markHeadsUpSeen(); + // Then it should NOT stay on screen anymore + assertThat(row.mustStayOnScreen()).isFalse(); + } + + @Test + @EnableFlags(com.android.systemui.Flags.FLAG_NOTIFICATIONS_PINNED_HUN_IN_SHADE) + public void mustStayOnScreen_isPinned_markedAsSeen() throws Exception { + final ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + // When a HUN is pinned + row.setHeadsUp(true); + row.setPinnedStatus(PinnedStatus.PinnedBySystem); + //Then it must stay on screen + assertThat(row.mustStayOnScreen()).isTrue(); + // And when the user has seen it + row.markHeadsUpSeen(); + // Then it should still stay on screen + assertThat(row.mustStayOnScreen()).isTrue(); + } + + @Test + @DisableFlags(com.android.systemui.Flags.FLAG_NOTIFICATIONS_PINNED_HUN_IN_SHADE) + public void mustStayOnScreen_isPinned_markedAsSeen_false() throws Exception { + final ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + // When a HUN is pinned + row.setHeadsUp(true); + row.setPinnedStatus(PinnedStatus.PinnedBySystem); + //Then it must stay on screen + assertThat(row.mustStayOnScreen()).isTrue(); + // And when the user has seen it + row.markHeadsUpSeen(); + // Then it should NOT stay on screen anymore + assertThat(row.mustStayOnScreen()).isFalse(); + } + private void setDrawableIconsInImageView(CachingIconView icon, Drawable iconDrawable, Drawable rightIconDrawable) { ImageView iconView = mock(ImageView.class); diff --git a/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt index 2850ab7b1e41..f893aba240fc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt @@ -19,9 +19,7 @@ import android.app.WallpaperManager import android.content.applicationContext import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.wallpaperManager: WallpaperManager by Fixture { WallpaperManager.getInstance(applicationContext) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt index c9458125e762..dfcda222e54f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt @@ -51,7 +51,6 @@ import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent @@ -148,7 +147,6 @@ interface SysUITestComponent<out T> { val underTest: T } -@OptIn(ExperimentalCoroutinesApi::class) fun <T : SysUITestComponent<*>> T.runTest(block: suspend T.() -> Unit): Unit = testScope.runTest { // Access underTest immediately to force Dagger to instantiate it prior to the test running @@ -157,7 +155,6 @@ fun <T : SysUITestComponent<*>> T.runTest(block: suspend T.() -> Unit): Unit = block() } -@OptIn(ExperimentalCoroutinesApi::class) fun SysUITestComponent<*>.runCurrent() = testScope.runCurrent() fun <T> SysUITestComponent<*>.collectLastValue( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt index a7917a0866bb..3c264b9d6a81 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt @@ -28,7 +28,6 @@ import com.android.systemui.dagger.SysUISingleton import dagger.Binds import dagger.Module import dagger.Provides -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -260,7 +259,6 @@ class FakeAuthenticationRepository(private val currentTime: () -> Long) : Authen } } -@OptIn(ExperimentalCoroutinesApi::class) @Module(includes = [FakeAuthenticationRepositoryModule.Bindings::class]) object FakeAuthenticationRepositoryModule { @Provides diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt index 79d58a1d4e40..e3bd6fa27d4c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt @@ -27,9 +27,7 @@ import com.android.systemui.keyguard.ui.viewmodel.sideFpsProgressBarViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.sideFpsOverlayViewBinder by Fixture { SideFpsOverlayViewBinder( applicationScope = applicationCoroutineScope, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelKosmos.kt index e2386a6a42b4..220bb90303b8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelKosmos.kt @@ -23,9 +23,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.statusbar.phone.systemUIDialogManager import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryUdfpsTouchOverlayViewModel by Fixture { DeviceEntryUdfpsTouchOverlayViewModel( deviceEntryIconViewModel = deviceEntryIconViewModel, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt index de038559fc38..e79c089361af 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt @@ -22,9 +22,7 @@ import com.android.systemui.biometrics.domain.interactor.sideFpsSensorInteractor import com.android.systemui.keyguard.domain.interactor.deviceEntrySideFpsOverlayInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.sideFpsOverlayViewModel by Fixture { SideFpsOverlayViewModel( applicationContext = applicationContext, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt index 5c5969d359c3..7de71ff44bb1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.bouncer.ui.viewmodel import android.content.applicationContext @@ -30,7 +28,6 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.user.ui.viewmodel.userSwitcherViewModel import com.android.systemui.util.time.systemClock -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.bouncerMessageViewModel by Fixture { BouncerMessageViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt index 72541540226c..3bfd95816cf0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.bouncer.ui.viewmodel import android.app.admin.devicePolicyManager @@ -34,7 +32,6 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.user.domain.interactor.selectedUserInteractor import com.android.systemui.user.ui.viewmodel.userSwitcherViewModel -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.StateFlow val Kosmos.bouncerUserActionsViewModel by Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt index 5e870b19681b..163625747d85 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt @@ -25,6 +25,7 @@ import kotlinx.coroutines.flow.map /** Fake implementation of [CommunalPrefsRepository] */ class FakeCommunalPrefsRepository : CommunalPrefsRepository { private val _isCtaDismissed = MutableStateFlow<Set<UserInfo>>(emptySet()) + private val _isHubOnboardingismissed = MutableStateFlow<Set<UserInfo>>(emptySet()) override fun isCtaDismissed(user: UserInfo): Flow<Boolean> = _isCtaDismissed.map { it.contains(user) } @@ -32,4 +33,12 @@ class FakeCommunalPrefsRepository : CommunalPrefsRepository { override suspend fun setCtaDismissed(user: UserInfo) { _isCtaDismissed.value = _isCtaDismissed.value.toMutableSet().apply { add(user) } } + + override fun isHubOnboardingDismissed(user: UserInfo): Flow<Boolean> = + _isHubOnboardingismissed.map { it.contains(user) } + + override suspend fun setHubOnboardingDismissed(user: UserInfo) { + _isHubOnboardingismissed.value = + _isHubOnboardingismissed.value.toMutableSet().apply { add(user) } + } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt index 82454817ecbb..b3c1411243c1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt @@ -5,7 +5,6 @@ import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.TransitionKey import com.android.systemui.communal.shared.model.CommunalScenes import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -16,7 +15,6 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch /** Fake implementation of [CommunalSceneRepository]. */ -@OptIn(ExperimentalCoroutinesApi::class) class FakeCommunalSceneRepository( private val applicationScope: CoroutineScope, override val currentScene: MutableStateFlow<SceneKey> = diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/HubOnboardingInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/HubOnboardingInteractorKosmos.kt new file mode 100644 index 000000000000..9db4e4f4b8f2 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/HubOnboardingInteractorKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.domain.interactor + +import com.android.systemui.communal.data.repository.communalSettingsRepository +import com.android.systemui.kosmos.Kosmos + +val Kosmos.hubOnboardingInteractor: HubOnboardingInteractor by + Kosmos.Fixture { + HubOnboardingInteractor( + communalSceneInteractor = communalSceneInteractor, + communalSettingsRepository = communalSettingsRepository, + communalPrefsInteractor = communalPrefsInteractor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/data/repository/FakePosturingRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/data/repository/FakePosturingRepository.kt new file mode 100644 index 000000000000..8a597a61ee78 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/data/repository/FakePosturingRepository.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.posturing.data.repository + +import com.android.systemui.communal.posturing.shared.model.PosturedState +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakePosturingRepository : PosturingRepository { + private val _postured = MutableStateFlow<PosturedState>(PosturedState.Unknown) + + override val posturedState: StateFlow<PosturedState> = _postured.asStateFlow() + + fun setPosturedState(state: PosturedState) { + _postured.value = state + } +} + +val PosturingRepository.fake + get() = this as FakePosturingRepository diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeUserActionsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/data/repository/PosturingRepositoryKosmos.kt index 6345c4076412..105a3581b787 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeUserActionsViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/data/repository/PosturingRepositoryKosmos.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 The Android Open Source Project + * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,8 @@ * limitations under the License. */ -package com.android.systemui.shade.ui.viewmodel +package com.android.systemui.communal.posturing.data.repository import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.Kosmos.Fixture -import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeUserActionsViewModel -val Kosmos.notificationsShadeUserActionsViewModel: - NotificationsShadeUserActionsViewModel by Fixture { NotificationsShadeUserActionsViewModel() } +val Kosmos.posturingRepository by Kosmos.Fixture<PosturingRepository> { FakePosturingRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorKosmos.kt new file mode 100644 index 000000000000..53c9c6440c69 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/posturing/domain/interactor/PosturingInteractorKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.posturing.domain.interactor + +import com.android.systemui.communal.posturing.data.repository.posturingRepository +import com.android.systemui.kosmos.Kosmos + +val Kosmos.posturingInteractor by + Kosmos.Fixture<PosturingInteractor> { PosturingInteractor(repository = posturingRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt index 1ae8449d8b4d..7b0c09cd80a6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt @@ -26,9 +26,7 @@ import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTrans import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGlanceableHubTransitionViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.communalTransitionViewModel by Kosmos.Fixture { CommunalTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/HubOnboardingViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/HubOnboardingViewModelKosmos.kt new file mode 100644 index 000000000000..9cdaaf4b88f8 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/HubOnboardingViewModelKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.ui.viewmodel + +import com.android.systemui.communal.domain.interactor.hubOnboardingInteractor +import com.android.systemui.kosmos.Kosmos + +val Kosmos.hubOnboardingViewModel by + Kosmos.Fixture { HubOnboardingViewModel(hubOnboardingInteractor = hubOnboardingInteractor) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/TestCoroutineSchedulerUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/TestCoroutineSchedulerUtils.kt index 84e2a5c7d4c2..2fb73264b3d4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/TestCoroutineSchedulerUtils.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/TestCoroutineSchedulerUtils.kt @@ -13,12 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.coroutines import kotlin.time.Duration -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestCoroutineScheduler /** diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt index cdeade1876a7..2a46437ed33e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt @@ -22,9 +22,7 @@ import com.android.systemui.deviceentry.ui.viewmodel.DeviceEntryUdfpsAccessibili import com.android.systemui.keyguard.ui.viewmodel.deviceEntryForegroundIconViewModel import com.android.systemui.keyguard.ui.viewmodel.deviceEntryIconViewModel import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryUdfpsAccessibilityOverlayViewModel by Kosmos.Fixture { DeviceEntryUdfpsAccessibilityOverlayViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt index 3070cf4c06ad..015d4ddcd54e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt @@ -17,9 +17,7 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.authRippleInteractor by Kosmos.Fixture { AuthRippleInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt index 77d39f066e08..6b6488122b68 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt @@ -20,9 +20,7 @@ import android.content.res.mainResources import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor import com.android.systemui.keyguard.domain.interactor.devicePostureInteractor import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.biometricMessageInteractor by Kosmos.Fixture { BiometricMessageInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractorKosmos.kt index 1bd105620813..281782ad726a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractorKosmos.kt @@ -14,13 +14,10 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.keyguard.data.repository.biometricSettingsRepository import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.deviceEntryBiometricAuthInteractor by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricSettingsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricSettingsInteractorKosmos.kt index 4fcf43a2a055..44755897f88e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricSettingsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricSettingsInteractorKosmos.kt @@ -18,9 +18,7 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.keyguard.data.repository.biometricSettingsRepository import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryBiometricSettingsInteractor by Kosmos.Fixture { DeviceEntryBiometricSettingsInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorKosmos.kt index 4357289b227e..3c08e5c55349 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorKosmos.kt @@ -14,13 +14,10 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.biometrics.data.repository.facePropertyRepository import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.deviceEntryBiometricsAllowedInteractor by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt index 3dfe0eea500f..33f8f40677af 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import android.content.applicationContext @@ -36,7 +34,6 @@ import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.user.data.repository.userRepository import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.faceAuthLogger by Kosmos.Fixture { mock<FaceAuthenticationLogger>() } val Kosmos.deviceEntryFaceAuthInteractor by diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorKosmos.kt index 66d3709d14dc..4a489ab2773c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import android.content.res.mainResources import com.android.systemui.keyguard.data.repository.deviceEntryFaceAuthRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.deviceEntryFaceAuthStatusInteractor by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorKosmos.kt index ebed922c423e..4d767e57e631 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.deviceEntryFingerprintAuthInteractor by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt index 490b89bf6b13..6f570a86b19e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import com.android.keyguard.logging.biometricUnlockLogger @@ -27,9 +25,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardBypassInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.util.time.systemClock -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.deviceEntryHapticsInteractor by Kosmos.Fixture { DeviceEntryHapticsInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt index 096022ce1507..1d3fd300da06 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt @@ -24,9 +24,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryInteractor by Kosmos.Fixture { DeviceEntryInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorKosmos.kt index f91a044ad802..845d481cbbb7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorKosmos.kt @@ -27,9 +27,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.statusbar.phone.dozeScrimController -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntrySourceInteractor by Kosmos.Fixture { DeviceEntrySourceInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt index 81123d09b43a..44d3c33c95fb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor @@ -23,7 +21,6 @@ import com.android.systemui.keyguard.data.repository.biometricSettingsRepository import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.deviceEntryUdfpsInteractor by Fixture { DeviceEntryUdfpsInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/FaceHelpMessageDeferralInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/FaceHelpMessageDeferralInteractorKosmos.kt index 724e943c9f55..79a9c57169a3 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/FaceHelpMessageDeferralInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/FaceHelpMessageDeferralInteractorKosmos.kt @@ -19,9 +19,7 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.biometrics.domain.faceHelpMessageDeferralFactory import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.faceHelpMessageDeferralInteractor by Kosmos.Fixture { FaceHelpMessageDeferralInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorKosmos.kt index 3680e651246b..3d5c99cf180a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorKosmos.kt @@ -27,9 +27,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.plugins.activityStarter import com.android.systemui.power.domain.interactor.powerInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.occludingAppDeviceEntryInteractor by Kosmos.Fixture { OccludingAppDeviceEntryInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt index 2fead91b430a..199a4a4d932c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt @@ -26,9 +26,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.util.sensors.asyncSensorManager -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.liftToRunFaceAuthBinder by Kosmos.Fixture { LiftToRunFaceAuthBinder( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeFocusedDisplayRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeFocusedDisplayRepository.kt index 83df5d874ad6..ad9370f7ac84 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeFocusedDisplayRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeFocusedDisplayRepository.kt @@ -33,7 +33,7 @@ class FakeFocusedDisplayRepository @Inject constructor() : FocusedDisplayReposit override val focusedDisplayId: StateFlow<Int> get() = flow.asStateFlow() - suspend fun emit(focusedDisplay: Int) = flow.emit(focusedDisplay) + suspend fun setDisplayId(focusedDisplay: Int) = flow.emit(focusedDisplay) } @Module diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt index 60a6f3d904d4..0192fa47b434 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt @@ -32,6 +32,7 @@ import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategories import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperInputDeviceRepository import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperTestHelper +import com.android.systemui.keyboard.shortcut.data.source.AccessibilityShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.AppCategoriesShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.CurrentAppShortcutsSource import com.android.systemui.keyboard.shortcut.data.source.InputShortcutsSource @@ -78,6 +79,9 @@ var Kosmos.shortcutHelperInputShortcutsSource: KeyboardShortcutGroupsSource by var Kosmos.shortcutHelperCurrentAppShortcutsSource: KeyboardShortcutGroupsSource by Kosmos.Fixture { CurrentAppShortcutsSource(windowManager) } +val Kosmos.shortcutHelperAccessibilityShortcutsSource: KeyboardShortcutGroupsSource by + Kosmos.Fixture { AccessibilityShortcutsSource(mainResources) } + val Kosmos.shortcutHelperExclusions by Kosmos.Fixture { ShortcutHelperExclusions(applicationContext) } @@ -100,6 +104,7 @@ val Kosmos.defaultShortcutCategoriesRepository by shortcutHelperAppCategoriesShortcutsSource, shortcutHelperInputShortcutsSource, shortcutHelperCurrentAppShortcutsSource, + shortcutHelperAccessibilityShortcutsSource, shortcutHelperInputDeviceRepository, shortcutCategoriesUtils, ) @@ -154,7 +159,7 @@ val Kosmos.shortcutHelperCoreStartable by shortcutHelperStateRepository, activityStarter, testScope, - customInputGesturesRepository + customInputGesturesRepository, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigKosmos.kt deleted file mode 100644 index 568324832b33..000000000000 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigKosmos.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.keyguard.data.quickaffordance - -import android.content.applicationContext -import com.android.systemui.communal.data.repository.communalSceneRepository -import com.android.systemui.communal.domain.interactor.communalInteractor -import com.android.systemui.communal.domain.interactor.communalSettingsInteractor -import com.android.systemui.kosmos.Kosmos -import com.android.systemui.scene.domain.interactor.sceneInteractor - -val Kosmos.glanceableHubQuickAffordanceConfig by - Kosmos.Fixture { - GlanceableHubQuickAffordanceConfig( - context = applicationContext, - communalInteractor = communalInteractor, - communalSceneRepository = communalSceneRepository, - communalSettingsInteractor = communalSettingsInteractor, - sceneInteractor = sceneInteractor, - ) - } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt index d59b5d56db3f..a91ed0f4b904 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt @@ -68,6 +68,7 @@ val Kosmos.defaultKeyguardBlueprint by keyguardSliceViewSection = mock(), udfpsAccessibilityOverlaySection = mock(), accessibilityActionsSection = mock(), + aodPromotedNotificationSection = mock(), ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt index 40131c772de7..26ebe2e41a17 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.domain.interactor import android.content.applicationContext @@ -24,7 +22,6 @@ import com.android.systemui.doze.util.burnInHelperWrapper import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.burnInInteractor by Fixture { BurnInInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractorKosmos.kt index 75eb3c9ad7ad..b920dbf88e77 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractorKosmos.kt @@ -18,9 +18,7 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.keyguard.data.repository.devicePostureRepository import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.devicePostureInteractor by Kosmos.Fixture { DevicePostureInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt index ce317d43e988..7b0d208298d0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt @@ -24,9 +24,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.fromAlternateBouncerTransitionInteractor by Kosmos.Fixture { FromAlternateBouncerTransitionInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt index e6c98cd83b5e..d995b868a162 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt @@ -27,9 +27,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) var Kosmos.fromDreamingTransitionInteractor by Kosmos.Fixture { FromDreamingTransitionInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt index 09f5fd79eeca..1d7671170d5b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt @@ -25,9 +25,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.keyguardDismissActionInteractor by Kosmos.Fixture { KeyguardDismissActionInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt index 339210c07437..277c2ffa6e9a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt @@ -26,9 +26,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.user.domain.interactor.selectedUserInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.keyguardDismissInteractor by Kosmos.Fixture { KeyguardDismissInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractorKosmos.kt index b5d5d641b0fe..87109b17ef0e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractorKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.domain.interactor import com.android.systemui.keyguard.data.repository.keyguardSmartspaceRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.keyguardSmartspaceInteractor by Fixture { KeyguardSmartspaceInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt index 1a05d21cc30a..31fb36eb26db 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui import com.android.keyguard.logging.keyguardTransitionAnimationLogger import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.keyguardTransitionAnimationFlow by Fixture { KeyguardTransitionAnimationFlow( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt index 740d8919cbc0..697e7b9476ca 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt @@ -38,9 +38,7 @@ import com.android.systemui.log.logcatLogBuffer import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.alternateBouncerViewBinder by Kosmos.Fixture { AlternateBouncerViewBinder( @@ -52,7 +50,6 @@ val Kosmos.alternateBouncerViewBinder by ) } -@ExperimentalCoroutinesApi private val Kosmos.alternateBouncerDependencies by Kosmos.Fixture { AlternateBouncerDependencies( @@ -69,7 +66,6 @@ private val Kosmos.alternateBouncerDependencies by ) } -@ExperimentalCoroutinesApi private val Kosmos.alternateBouncerUdfpsIconViewModel by Kosmos.Fixture { AlternateBouncerUdfpsIconViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt index b7d9676040d0..938556e71cbb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor import com.android.systemui.deviceentry.domain.interactor.biometricMessageInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.util.time.systemClock -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.alternateBouncerMessageAreaViewModel by Kosmos.Fixture { AlternateBouncerMessageAreaViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt index 3ed9392bab2a..7d729e38fdca 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerToAodTransitionViewModel by Fixture { AlternateBouncerToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt index c6f07068aad4..71cfb40c11d6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsIntera import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.alternateBouncerToDozingTransitionViewModel by Fixture { AlternateBouncerToDozingTransitionViewModel( deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt index b943298f6b53..3ec0ee040269 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.statusbar.sysuiStatusBarStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerToGoneTransitionViewModel by Fixture { AlternateBouncerToGoneTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToLockscreenTransitionViewModelKosmos.kt index 6c644eee24ff..346580a91f9b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToLockscreenTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerToLockscreenTransitionViewModel by Fixture { AlternateBouncerToLockscreenTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToOccludedTransitionViewModelKosmos.kt index 71ad3c6689f7..87367b24fc7d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToOccludedTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToOccludedTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerToOccludedTransitionViewModel by Fixture { AlternateBouncerToOccludedTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelKosmos.kt index 79892442092c..7bf778deeab5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelKosmos.kt @@ -14,17 +14,13 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.alternateBouncerToPrimaryBouncerTransitionViewModel by Fixture { AlternateBouncerToPrimaryBouncerTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt index f1d87fe3abb7..3da27cb3c11d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInterac import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerViewModel by Fixture { AlternateBouncerViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelKosmos.kt index 92cfbef987f6..335ab84a0851 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerWindowViewModel by Fixture { AlternateBouncerWindowViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt index c3c2c8c95aad..1471ddbcea61 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInterac import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.aodBurnInViewModel by Fixture { AodBurnInViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt index b6f278c1b466..6aad53a5d067 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.aodToGoneTransitionViewModel by Fixture { AodToGoneTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt index b8fcec648393..25a8d5d201be 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.shade.domain.interactor.shadeInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.aodToLockscreenTransitionViewModel by Fixture { AodToLockscreenTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt index 8d066fc05996..3b33ee47bc41 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.aodToOccludedTransitionViewModel by Fixture { AodToOccludedTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerViewModelKosmos.kt index faa290be6129..ae411367fcfc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.aodToPrimaryBouncerTransitionViewModel by Fixture { AodToPrimaryBouncerTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt index 9774e4aa51a5..0b364eafb418 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor @@ -25,7 +23,6 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.statusbar.sysuiStatusBarStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.bouncerToGoneFlows by Fixture { BouncerToGoneFlows( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt index fc4f3a553d51..bd0045501ec8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt @@ -21,9 +21,7 @@ import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryBackgroundViewModel by Fixture { DeviceEntryBackgroundViewModel( context = applicationContext, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt index 4f638d0e4a38..1a4bd338ade7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt @@ -23,9 +23,7 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsIntera import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryForegroundIconViewModel by Fixture { DeviceEntryForegroundViewModel( context = applicationContext, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt index 67fa857a1ecd..f8393d537f82 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt @@ -29,7 +29,6 @@ import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testScope import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.fakeDeviceEntryIconViewModelTransition by Fixture { FakeDeviceEntryIconTransition() } @@ -37,7 +36,6 @@ val Kosmos.deviceEntryIconViewModelTransitionsMock by Fixture { setOf<DeviceEntryIconTransition>(fakeDeviceEntryIconViewModelTransition) } -@ExperimentalCoroutinesApi val Kosmos.deviceEntryIconViewModel by Fixture { DeviceEntryIconViewModel( transitions = deviceEntryIconViewModelTransitionsMock, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt index ef10459b45cb..87c3dbf9487e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt @@ -19,9 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dozingToGlanceableHubTransitionViewModel by Fixture { DozingToGlanceableHubTransitionViewModel(animationFlow = keyguardTransitionAnimationFlow) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt index 36ddc29b8914..7c066036b131 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt @@ -19,9 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dozingToGoneTransitionViewModel by Fixture { DozingToGoneTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt index de52d848e94b..46f9f8dcd962 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt @@ -19,9 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dozingToLockscreenTransitionViewModel by Fixture { DozingToLockscreenTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToOccludedTransitionViewModelKosmos.kt index 8162520e5d88..25865ae8700f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToOccludedTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToOccludedTransitionViewModelKosmos.kt @@ -18,9 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dozingToOccludedTransitionViewModel by Kosmos.Fixture { DozingToOccludedTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt index d3ccb297fc9d..39f9530bcb17 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dozingToPrimaryBouncerTransitionViewModel by Fixture { DozingToPrimaryBouncerTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToAodTransitionViewModelKosmos.kt index b5f0b897deba..ec1f906dc179 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToAodTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.dreamingToAodTransitionViewModel by Fixture { DreamingToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGoneTransitionViewModelKosmos.kt index f389142554b1..1e832bdf82dd 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGoneTransitionViewModelKosmos.kt @@ -18,9 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dreamingToGoneTransitionViewModel by Kosmos.Fixture { DreamingToGoneTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt index d06bab2f5345..1d0a210110ed 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt @@ -19,9 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dreamingToLockscreenTransitionViewModel by Fixture { DreamingToLockscreenTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt index b1c21b8fa6cf..bb1098f14ea6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt @@ -14,17 +14,13 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.glanceableHubToLockscreenTransitionViewModel by Fixture { GlanceableHubToLockscreenTransitionViewModel( configurationInteractor = configurationInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt index 8549a30c346e..2d24ef2fcfee 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor @@ -23,7 +21,6 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.power.domain.interactor.powerInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.goneToAodTransitionViewModel by Fixture { GoneToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt index b19d4e87e68c..3f7348be8fe5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsIntera import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.goneToDozingTransitionViewModel by Fixture { GoneToDozingTransitionViewModel( deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt index b267a962a1ff..86ef95cbab4c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.goneToDreamingTransitionViewModel by Fixture { GoneToDreamingTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModelKosmos.kt index 1b6fa064854d..4322a887928a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.goneToLockscreenTransitionViewModel by Fixture { GoneToLockscreenTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelFactoryKosmos.kt new file mode 100644 index 000000000000..16d3fdc26613 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModelFactoryKosmos.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor + +val Kosmos.keyguardMediaViewModelFactory by + Kosmos.Fixture { + object : KeyguardMediaViewModel.Factory { + override fun create(): KeyguardMediaViewModel { + return KeyguardMediaViewModel(mediaCarouselInteractor, keyguardInteractor) + } + } + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt index 1c0f97d294df..40b8e0e62b03 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.communal.domain.interactor.communalInteractor @@ -31,7 +29,6 @@ import com.android.systemui.statusbar.notification.icon.ui.viewmodel.notificatio import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor import com.android.systemui.statusbar.phone.dozeParameters import com.android.systemui.statusbar.phone.screenOffAnimationController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.keyguardRootViewModel by Fixture { KeyguardRootViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt index f45e33bf6865..5234b5bd17e2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor @@ -23,7 +21,6 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.power.domain.interactor.powerInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.lockscreenToAodTransitionViewModel by Fixture { LockscreenToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt index aa8e9a8c9a8c..bf1af3c47674 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsIntera import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.lockscreenToDozingTransitionViewModel by Fixture { LockscreenToDozingTransitionViewModel( deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt index 56d5ff6e30eb..1246b9455b4b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.lockscreenToDreamingTransitionViewModel by Fixture { LockscreenToDreamingTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt index 471381f7a13f..0e961ccaf07b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt @@ -14,17 +14,13 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.lockscreenToGlanceableHubTransitionViewModel by Fixture { LockscreenToGlanceableHubTransitionViewModel( configurationInteractor = configurationInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt index 7a023ee29299..172b4f8db92b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.statusbar.sysuiStatusBarStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.lockscreenToGoneTransitionViewModel by Fixture { LockscreenToGoneTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt index 9953d39e9a49..abd29cadb8f7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.lockscreenToOccludedTransitionViewModel by Fixture { LockscreenToOccludedTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt index 68280d7622fd..b5c67b66ae5f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.lockscreenToPrimaryBouncerTransitionViewModel by Fixture { LockscreenToPrimaryBouncerTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAlternateBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAlternateBouncerTransitionViewModelKosmos.kt index 2acd1b40af3e..39a545a8c451 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAlternateBouncerTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAlternateBouncerTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.occludedToAlternateBouncerTransitionViewModel by Fixture { OccludedToAlternateBouncerTransitionViewModel(animationFlow = keyguardTransitionAnimationFlow) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt index b7867b6cabde..dd6d9acaa33e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.occludedToAodTransitionViewModel by Fixture { OccludedToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt index 4196e54a085d..4e8896ab11c1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.occludedToDozingTransitionViewModel by Fixture { OccludedToDozingTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModelKosmos.kt index 3b96912b53c6..70e9af1b1058 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.occludedToGoneTransitionViewModel by Fixture { OccludedToGoneTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt index f86e9b7216ce..5b1d8f126f84 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInterac import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.occludedToLockscreenTransitionViewModel by Fixture { OccludedToLockscreenTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModelKosmos.kt index 5d62a0f4a0cf..579819f6d265 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.offToLockscreenTransitionViewModel by Fixture { OffToLockscreenTransitionViewModel(animationFlow = keyguardTransitionAnimationFlow) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt index 043a49f5f640..73ef4328657a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor @@ -23,7 +21,6 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.primaryBouncerToAodTransitionViewModel by Fixture { PrimaryBouncerToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt index 59ea2c93089c..99297351bdaa 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt @@ -21,9 +21,7 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.primaryBouncerToDozingTransitionViewModel by Fixture { PrimaryBouncerToDozingTransitionViewModel( deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt index b470ab12828b..acf0827b1614 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.statusbar.sysuiStatusBarStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.primaryBouncerToGoneTransitionViewModel by Fixture { PrimaryBouncerToGoneTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt index c3447753a86d..bd5a21195795 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.primaryBouncerToLockscreenTransitionViewModel by Fixture { PrimaryBouncerToLockscreenTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModelKosmos.kt index 8da16fc4e855..e38c419a97f2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import android.content.applicationContext @@ -29,7 +27,6 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.statusbar.phone.dozeServiceHost -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.sideFpsProgressBarViewModel by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt index 439df543b9fb..a4c2cc275e44 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt @@ -9,7 +9,6 @@ import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.settings.brightness.ui.BrightnessWarningToast import com.android.systemui.util.mockito.mock import kotlin.coroutines.CoroutineContext -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -73,7 +72,6 @@ fun <T> Kosmos.collectValues(flow: Flow<T>): FlowValue<List<T>> = testScope.coll * If you want to assert on a [Flow] that is not a [StateFlow], please use * [TestScope.collectLastValue], to make sure that the desired value is captured when emitted. */ -@OptIn(ExperimentalCoroutinesApi::class) fun <T> TestScope.currentValue(stateFlow: StateFlow<T>): T { val values = mutableListOf<T>() val job = backgroundScope.launch { stateFlow.collect(values::add) } @@ -90,7 +88,6 @@ fun <T> Kosmos.currentValue(fn: () -> T) = testScope.currentValue(fn) * Retrieve the result of [fn] after running all pending tasks. Do not use to retrieve the value of * a flow directly; for that, use either `currentValue(StateFlow)` or [collectLastValue] */ -@OptIn(ExperimentalCoroutinesApi::class) fun <T> TestScope.currentValue(fn: () -> T): T { runCurrent() return fn() @@ -102,7 +99,6 @@ fun <T> Kosmos.currentValue(stateFlow: StateFlow<T>): T { } /** Safely verify that a mock has been called after the test scope has caught up */ -@OptIn(ExperimentalCoroutinesApi::class) fun <T> TestScope.verifyCurrent(mock: T): T { runCurrent() return verify(mock) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt index 39f1ad42797b..35e90f06ddde 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.kosmos import android.content.applicationContext @@ -92,7 +90,6 @@ import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisionin import com.android.systemui.statusbar.ui.viewmodel.keyguardStatusBarViewModel import com.android.systemui.util.time.systemClock import com.android.systemui.volume.domain.interactor.volumeDialogInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi /** * Helper for using [Kosmos] from Java. diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt index 5acadd7f192a..2ef3f4a70998 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt @@ -23,7 +23,6 @@ import com.android.systemui.mediaprojection.data.repository.realMediaProjectionR import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher val Kosmos.fakeActivityTaskManager by Kosmos.Fixture { FakeActivityTaskManager() } @@ -47,5 +46,4 @@ val Kosmos.taskSwitcherInteractor by val Kosmos.taskSwitcherViewModel by Kosmos.Fixture { TaskSwitcherNotificationViewModel(taskSwitcherInteractor, testDispatcher) } -@OptIn(ExperimentalCoroutinesApi::class) fun taskSwitcherKosmos() = Kosmos().apply { testDispatcher = UnconfinedTestDispatcher() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt index 49957f0b43cc..65e580cafcb5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt @@ -39,9 +39,7 @@ import com.android.systemui.shade.largeScreenHeaderHelper import com.android.systemui.shade.transition.largeScreenShadeInterpolator import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor import com.android.systemui.statusbar.sysuiStatusBarStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.qsFragmentComposeViewModelFactory by Kosmos.Fixture { object : QSFragmentComposeViewModel.Factory { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt index aa6ce9a433df..f8fa5db4ddf7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt @@ -23,6 +23,7 @@ import com.android.systemui.qs.panels.ui.viewmodel.editModeViewModel import com.android.systemui.qs.panels.ui.viewmodel.quickQuickSettingsViewModelFactory import com.android.systemui.qs.panels.ui.viewmodel.tileGridViewModel import com.android.systemui.qs.panels.ui.viewmodel.toolbar.toolbarViewModelFactory +import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory val Kosmos.quickSettingsContainerViewModelFactory by Kosmos.Fixture { @@ -33,6 +34,7 @@ val Kosmos.quickSettingsContainerViewModelFactory by return QuickSettingsContainerViewModel( brightnessSliderViewModelFactory, quickQuickSettingsViewModelFactory, + shadeHeaderViewModelFactory, supportsBrightnessMirroring, tileGridViewModel, editModeViewModel, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt index a4a63ec6ca21..9d18fbfccb36 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.scene.domain.resolver import com.android.compose.animation.scene.SceneKey @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.scene.shared.model.SceneFamilies -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.sceneFamilyResolvers: Map<SceneKey, SceneResolver> get() = mapOf(SceneFamilies.Home to homeSceneFamilyResolver) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/ScrimStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/ScrimStartableKosmos.kt index b64c84075936..12b46536b2a2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/ScrimStartableKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/ScrimStartableKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.scene.domain.startable import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor @@ -31,7 +29,6 @@ import com.android.systemui.settings.brightness.domain.interactor.brightnessMirr import com.android.systemui.statusbar.phone.dozeServiceHost import com.android.systemui.statusbar.phone.scrimController import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.scrimStartable by Fixture { ScrimStartable( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/StatusBarStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/StatusBarStartableKosmos.kt index ee69c30fe6b9..881d110dff25 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/StatusBarStartableKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/StatusBarStartableKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.scene.domain.startable import android.content.applicationContext @@ -33,7 +31,6 @@ import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.user.domain.interactor.selectedUserInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.statusBarStartable by Fixture { StatusBarStartable( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt index b9f0c9a70d3d..e2b2026550f1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.shade import com.android.systemui.assist.AssistManager @@ -39,7 +37,6 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.deviceProvisionedController import com.android.systemui.statusbar.window.StatusBarWindowControllerStore import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.shadeControllerSceneImpl by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt index b3d89dbb834d..e143324baeae 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt @@ -25,7 +25,6 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.data.repository.FakeShadeRepository import com.android.systemui.shade.data.repository.ShadeRepository -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.TestScope @@ -193,7 +192,6 @@ class ShadeTestUtilLegacyImpl( } /** Sets up shade state for tests when the scene container flag is enabled. */ -@OptIn(ExperimentalCoroutinesApi::class) class ShadeTestUtilSceneImpl( val testScope: TestScope, val sceneInteractor: SceneInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt index aaef27d257c5..d9a348d93533 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt @@ -16,12 +16,15 @@ package com.android.systemui.shade.data.repository +import com.android.systemui.display.data.repository.FakeFocusedDisplayRepository import com.android.systemui.display.data.repository.displayRepository import com.android.systemui.keyguard.data.repository.keyguardRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.shade.display.AnyExternalShadeDisplayPolicy import com.android.systemui.shade.display.DefaultDisplayShadePolicy +import com.android.systemui.shade.display.FakeShadeDisplayPolicy +import com.android.systemui.shade.display.FocusShadeDisplayPolicy import com.android.systemui.shade.display.ShadeDisplayPolicy import com.android.systemui.shade.display.ShadeExpansionIntent import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy @@ -46,8 +49,6 @@ val Kosmos.statusBarTouchShadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy by StatusBarTouchShadeDisplayPolicy( displayRepository = displayRepository, backgroundScope = testScope.backgroundScope, - keyguardRepository = keyguardRepository, - shadeOnDefaultDisplayWhenLocked = false, shadeInteractor = { shadeInteractor }, notificationElement = { notificationElement }, qsShadeElement = { qsElement }, @@ -55,13 +56,15 @@ val Kosmos.statusBarTouchShadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy by } val Kosmos.shadeExpansionIntent: ShadeExpansionIntent by Kosmos.Fixture { statusBarTouchShadeDisplayPolicy } -val Kosmos.shadeDisplaysRepository: MutableShadeDisplaysRepository by +val Kosmos.shadeDisplaysRepository: ShadeDisplaysRepository by Kosmos.Fixture { ShadeDisplaysRepositoryImpl( bgScope = testScope.backgroundScope, globalSettings = fakeGlobalSettings, policies = shadeDisplayPolicies, defaultPolicy = defaultShadeDisplayPolicy, + shadeOnDefaultDisplayWhenLocked = true, + keyguardRepository = keyguardRepository, ) } @@ -71,8 +74,16 @@ val Kosmos.shadeDisplayPolicies: Set<ShadeDisplayPolicy> by defaultShadeDisplayPolicy, anyExternalShadeDisplayPolicy, statusBarTouchShadeDisplayPolicy, + FakeShadeDisplayPolicy, ) } val Kosmos.fakeShadeDisplaysRepository: FakeShadeDisplayRepository by Kosmos.Fixture { FakeShadeDisplayRepository() } +val Kosmos.fakeFocusedDisplayRepository: FakeFocusedDisplayRepository by + Kosmos.Fixture { FakeFocusedDisplayRepository() } + +val Kosmos.focusShadeDisplayPolicy: FocusShadeDisplayPolicy by + Kosmos.Fixture { + FocusShadeDisplayPolicy(focusedDisplayRepository = fakeFocusedDisplayRepository) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/PrivacyChipInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/PrivacyChipInteractorKosmos.kt index 7334286f00c4..b92ad9439936 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/PrivacyChipInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/PrivacyChipInteractorKosmos.kt @@ -21,6 +21,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.privacy.privacyDialogController import com.android.systemui.privacy.privacyDialogControllerV2 import com.android.systemui.shade.data.repository.fakePrivacyChipRepository +import com.android.systemui.shade.data.repository.shadeDialogContextInteractor import com.android.systemui.statusbar.policy.deviceProvisionedController var Kosmos.privacyChipInteractor: PrivacyChipInteractor by @@ -31,5 +32,6 @@ var Kosmos.privacyChipInteractor: PrivacyChipInteractor by privacyDialogController = privacyDialogController, privacyDialogControllerV2 = privacyDialogControllerV2, deviceProvisionedController = deviceProvisionedController, + shadeDialogContextInteractor = shadeDialogContextInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt index 923de2dcbf68..170d067b5c0c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt @@ -18,12 +18,16 @@ package com.android.systemui.shade.domain.interactor import android.content.mockedContext import android.window.WindowContext +import com.android.systemui.common.ui.data.repository.configurationRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.shade.ShadeDisplayChangeLatencyTracker import com.android.systemui.shade.ShadeWindowLayoutParams import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository import com.android.systemui.shade.data.repository.shadeExpansionIntent +import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor +import com.android.systemui.statusbar.notification.row.notificationRebindingTracker +import com.android.systemui.statusbar.notification.stack.notificationStackRebindingHider import java.util.Optional import org.mockito.kotlin.any import org.mockito.kotlin.mock @@ -46,10 +50,14 @@ val Kosmos.shadeDisplaysInteractor by ShadeDisplaysInteractor( fakeShadeDisplaysRepository, mockedWindowContext, + configurationRepository, testScope.backgroundScope, testScope.backgroundScope.coroutineContext, mockedShadeDisplayChangeLatencyTracker, Optional.of(shadeExpandedStateInteractor), shadeExpansionIntent, + activeNotificationsInteractor, + notificationRebindingTracker, + Optional.of(notificationStackRebindingHider), ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt index f5b856df8835..7eb9f3472482 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt @@ -20,6 +20,7 @@ import android.content.applicationContext import com.android.systemui.broadcast.broadcastDispatcher import com.android.systemui.kosmos.Kosmos import com.android.systemui.plugins.activityStarter +import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.shade.domain.interactor.privacyChipInteractor import com.android.systemui.shade.domain.interactor.shadeHeaderClockInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor @@ -31,6 +32,7 @@ val Kosmos.shadeHeaderViewModel: ShadeHeaderViewModel by ShadeHeaderViewModel( context = applicationContext, activityStarter = activityStarter, + sceneInteractor = sceneInteractor, shadeInteractor = shadeInteractor, mobileIconsInteractor = mobileIconsInteractor, mobileIconsViewModel = mobileIconsViewModel, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt index 88bf9a5f2d5b..6593547f393d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt @@ -27,9 +27,7 @@ import com.android.systemui.statusbar.notificationLockscreenUserManager import com.android.systemui.statusbar.policy.keyguardStateController import com.android.systemui.statusbar.policy.sensitiveNotificationProtectionController import com.android.systemui.user.domain.interactor.selectedUserInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) var Kosmos.sensitiveContentCoordinator: SensitiveContentCoordinator by Kosmos.Fixture { SensitiveContentCoordinatorImpl( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt index 774782cc019c..dc7595f7f2e4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.statusbar.notification.icon.domain.interactor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor @@ -27,7 +25,6 @@ import com.android.systemui.statusbar.notification.data.repository.notifications import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.headsUpNotificationIconInteractor import com.android.wm.shell.bubbles.bubblesOptional -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alwaysOnDisplayNotificationIconsInteractor by Fixture { AlwaysOnDisplayNotificationIconsInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt index 3fddd47c25f0..6246d986f9e5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt @@ -380,6 +380,7 @@ class ExpandableNotificationRowBuilder( mSmartReplyController, Mockito.mock(IStatusBarService::class.java, STUB_ONLY), Mockito.mock(UiEventLogger::class.java, STUB_ONLY), + Mockito.mock(NotificationRebindingTracker::class.java, STUB_ONLY), ) row.setAboveShelfChangedListener {} mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/NotificationRebindingTrackerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/NotificationRebindingTrackerKosmos.kt new file mode 100644 index 000000000000..deac37a55717 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/NotificationRebindingTrackerKosmos.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.row + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor + +val Kosmos.notificationRebindingTracker by + Kosmos.Fixture { + NotificationRebindingTracker( + activeNotificationsInteractor = activeNotificationsInteractor, + bgScope = testScope.backgroundScope, + appScope = testScope.backgroundScope, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt index 65f4ec1c437c..d65a4a0532e3 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt @@ -23,9 +23,7 @@ import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.shade.transition.largeScreenShadeInterpolator import com.android.systemui.statusbar.notification.headsup.mockAvalancheController import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.ambientState by Fixture { AmbientState( /*context=*/ applicationContext, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerKosmos.kt index 569429f180df..73f296415a5a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerKosmos.kt @@ -21,3 +21,6 @@ import com.android.systemui.util.mockito.mock val Kosmos.notificationStackScrollLayoutController by Kosmos.Fixture { mock<NotificationStackScrollLayoutController>() } + +val Kosmos.notificationStackRebindingHider by + Kosmos.Fixture { mock<NotificationStackRebindingHider>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt index b1e9d89dfd42..e250575ad3fc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.statusbar.notification.stack.domain.interactor import android.content.applicationContext @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.shade.largeScreenHeaderHelper import com.android.systemui.statusbar.policy.splitShadeStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.sharedNotificationContainerInteractor by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt index 8461da77796d..45c56ae0ab7a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt @@ -60,9 +60,7 @@ import com.android.systemui.statusbar.notification.stack.domain.interactor.notif import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor import com.android.systemui.unfold.domain.interactor.unfoldTransitionInteractor import com.android.systemui.window.ui.viewmodel.fakeBouncerTransitions -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.sharedNotificationContainerViewModel by Fixture { SharedNotificationContainerViewModel( interactor = sharedNotificationContainerInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/BiometricUnlockController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/BiometricUnlockController.kt index f377e28bb51a..c87a20e660a1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/BiometricUnlockController.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/BiometricUnlockController.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.statusbar.phone import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.biometricUnlockController: BiometricUnlockController by Fixture { mock<BiometricUnlockController>() diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt index d0bf584d9a62..78140416cb40 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt @@ -31,9 +31,7 @@ import com.android.systemui.statusbar.notificationShadeWindowController import com.android.systemui.statusbar.policy.batteryController import com.android.systemui.statusbar.policy.deviceProvisionedController import com.android.systemui.statusbar.pulseExpansionHandler -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.dozeServiceHost: DozeServiceHost by Kosmos.Fixture { DozeServiceHost( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ManagedProfileControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ManagedProfileControllerKosmos.kt index ef04b9d907f1..7c8ad12ccf0d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ManagedProfileControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ManagedProfileControllerKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.statusbar.phone import android.testing.LeakCheck import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.utils.leaks.FakeManagedProfileController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.fakeManagedProfileController by Fixture { FakeManagedProfileController(LeakCheck()) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt index ddce4c896c14..4e15ea2d9377 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt @@ -18,7 +18,5 @@ package com.android.systemui.statusbar.phone import com.android.systemui.kosmos.Kosmos import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) var Kosmos.statusBarKeyguardViewManager by Kosmos.Fixture { mock<StatusBarKeyguardViewManager>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt index 7743a1c7e0cd..0d6ac4481742 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt @@ -47,9 +47,7 @@ import com.android.systemui.statusbar.notificationShadeWindowController import com.android.systemui.statusbar.policy.keyguardStateController import com.android.systemui.wmshell.bubblesManager import java.util.Optional -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.statusBarNotificationActivityStarter by Kosmos.Fixture { StatusBarNotificationActivityStarter( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt index 577620347991..a0d9227cc048 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt @@ -17,7 +17,6 @@ package com.android.systemui.util.coroutines import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.setMain @@ -28,7 +27,6 @@ import org.junit.runner.Description * Overrides main dispatcher to passed testDispatcher. You probably want to use it when using * viewModelScope which has hardcoded main dispatcher. */ -@OptIn(ExperimentalCoroutinesApi::class) class MainDispatcherRule(val testDispatcher: TestDispatcher) : TestWatcher() { override fun starting(description: Description) { Dispatchers.setMain(testDispatcher) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt index f3a8b14abab8..703d6ad83eac 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt @@ -20,10 +20,8 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.currentTime -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.systemClock by Kosmos.Fixture<SystemClock> { mock { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModuleKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModuleKosmos.kt index 0c814c566d63..556c34d85f8e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModuleKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModuleKosmos.kt @@ -16,13 +16,16 @@ package com.android.systemui.volume.panel.component.mediaoutput +import android.content.applicationContext import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.volume.panel.component.mediaoutput.domain.MediaOutputAvailabilityCriteria import com.android.systemui.volume.panel.component.mediaoutput.ui.composable.MediaOutputComponent import com.android.systemui.volume.panel.component.mediaoutput.ui.viewmodel.mediaOutputViewModel -import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria -import com.android.systemui.volume.panel.domain.availableCriteria var Kosmos.mediaOutputComponent: MediaOutputComponent by Kosmos.Fixture { MediaOutputComponent(mediaOutputViewModel) } -var Kosmos.mediaOutputAvailabilityCriteria: ComponentAvailabilityCriteria by - Kosmos.Fixture { availableCriteria } +var Kosmos.mediaOutputAvailabilityCriteria by + Kosmos.Fixture { + MediaOutputAvailabilityCriteria(applicationContext, testScope.backgroundScope) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractorKosmos.kt index ad30ea26c5b8..151f3d45b906 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractorKosmos.kt @@ -17,7 +17,9 @@ package com.android.systemui.window.domain.interactor import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.window.data.repository.windowRootViewBlurRepository val Kosmos.windowRootViewBlurInteractor by @@ -25,5 +27,7 @@ val Kosmos.windowRootViewBlurInteractor by WindowRootViewBlurInteractor( repository = windowRootViewBlurRepository, keyguardInteractor = keyguardInteractor, + keyguardTransitionInteractor = keyguardTransitionInteractor, + applicationScope = applicationCoroutineScope, ) } diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig index 7f0bf0375b4a..722255404dd1 100644 --- a/services/accessibility/accessibility.aconfig +++ b/services/accessibility/accessibility.aconfig @@ -145,6 +145,16 @@ flag { } flag { + name: "event_dispatcher_raw_event" + namespace: "accessibility" + description: "Fixes EventDispatcher#sendMotionEvent callers to properly provide raw event" + bug: "385812366" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "fix_drag_pointer_when_ending_drag" namespace: "accessibility" description: "Send the correct pointer id when transitioning from dragging to delegating states." diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java index 8b758d29a2ac..3415300ec8d1 100644 --- a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java +++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java @@ -16,7 +16,10 @@ package com.android.server.accessibility; -import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import static android.view.MotionEvent.BUTTON_PRIMARY; +import static android.view.accessibility.AccessibilityManager.AUTOCLICK_CURSOR_AREA_SIZE_DEFAULT; +import static android.view.accessibility.AccessibilityManager.AUTOCLICK_DELAY_DEFAULT; +import static android.view.accessibility.AccessibilityManager.AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT_DEFAULT; import static com.android.server.accessibility.AutoclickIndicatorView.SHOW_INDICATOR_DELAY_TIME; @@ -26,7 +29,6 @@ import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; -import android.graphics.PixelFormat; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; @@ -37,10 +39,11 @@ import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; import android.view.WindowManager; -import android.view.accessibility.AccessibilityManager; import androidx.annotation.VisibleForTesting; +import com.android.internal.accessibility.util.AccessibilityUtils; + /** * Implements "Automatically click on mouse stop" feature. * @@ -96,8 +99,7 @@ public class AutoclickController extends BaseEventStreamTransformation { initiateAutoclickIndicator(handler); } - mClickScheduler = - new ClickScheduler(handler, AccessibilityManager.AUTOCLICK_DELAY_DEFAULT); + mClickScheduler = new ClickScheduler(handler, AUTOCLICK_DELAY_DEFAULT); mAutoclickSettingsObserver = new AutoclickSettingsObserver(mUserId, handler); mAutoclickSettingsObserver.start( mContext.getContentResolver(), @@ -117,21 +119,8 @@ public class AutoclickController extends BaseEventStreamTransformation { mAutoclickIndicatorScheduler = new AutoclickIndicatorScheduler(handler); mAutoclickIndicatorView = new AutoclickIndicatorView(mContext); - final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); - layoutParams.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; - layoutParams.flags = - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE - | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; - layoutParams.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; - layoutParams.setFitInsetsTypes(0); - layoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - layoutParams.format = PixelFormat.TRANSLUCENT; - layoutParams.setTitle(AutoclickIndicatorView.class.getSimpleName()); - layoutParams.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; - mWindowManager = mContext.getSystemService(WindowManager.class); - mWindowManager.addView(mAutoclickIndicatorView, layoutParams); + mWindowManager.addView(mAutoclickIndicatorView, mAutoclickIndicatorView.getLayoutParams()); } @Override @@ -209,6 +198,11 @@ public class AutoclickController extends BaseEventStreamTransformation { private final Uri mAutoclickCursorAreaSizeSettingUri = Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE); + /** URI used to identify ignore minor cursor movement setting with content resolver. */ + private final Uri mAutoclickIgnoreMinorCursorMovementSettingUri = + Settings.Secure.getUriFor( + Settings.Secure.ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT); + private ContentResolver mContentResolver; private ClickScheduler mClickScheduler; private AutoclickIndicatorScheduler mAutoclickIndicatorScheduler; @@ -247,18 +241,32 @@ public class AutoclickController extends BaseEventStreamTransformation { mContentResolver = contentResolver; mClickScheduler = clickScheduler; mAutoclickIndicatorScheduler = autoclickIndicatorScheduler; - mContentResolver.registerContentObserver(mAutoclickDelaySettingUri, false, this, + mContentResolver.registerContentObserver( + mAutoclickDelaySettingUri, + /* notifyForDescendants= */ false, + /* observer= */ this, mUserId); // Initialize mClickScheduler's initial delay value. - onChange(true, mAutoclickDelaySettingUri); + onChange(/* selfChange= */ true, mAutoclickDelaySettingUri); if (Flags.enableAutoclickIndicator()) { // Register observer to listen to cursor area size setting change. mContentResolver.registerContentObserver( - mAutoclickCursorAreaSizeSettingUri, false, this, mUserId); + mAutoclickCursorAreaSizeSettingUri, + /* notifyForDescendants= */ false, + /* observer= */ this, + mUserId); // Initialize mAutoclickIndicatorView's initial size. - onChange(true, mAutoclickCursorAreaSizeSettingUri); + onChange(/* selfChange= */ true, mAutoclickCursorAreaSizeSettingUri); + + // Register observer to listen to ignore minor cursor movement setting change. + mContentResolver.registerContentObserver( + mAutoclickIgnoreMinorCursorMovementSettingUri, + /* notifyForDescendants= */ false, + /* observer= */ this, + mUserId); + onChange(/* selfChange= */ true, mAutoclickIgnoreMinorCursorMovementSettingUri); } } @@ -279,21 +287,41 @@ public class AutoclickController extends BaseEventStreamTransformation { @Override public void onChange(boolean selfChange, Uri uri) { if (mAutoclickDelaySettingUri.equals(uri)) { - int delay = Settings.Secure.getIntForUser( - mContentResolver, Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, - AccessibilityManager.AUTOCLICK_DELAY_DEFAULT, mUserId); - mClickScheduler.updateDelay(delay); - } - if (Flags.enableAutoclickIndicator() - && mAutoclickCursorAreaSizeSettingUri.equals(uri)) { - int size = + int delay = Settings.Secure.getIntForUser( mContentResolver, - Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE, - AccessibilityManager.AUTOCLICK_CURSOR_AREA_SIZE_DEFAULT, + Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, + AUTOCLICK_DELAY_DEFAULT, mUserId); - if (mAutoclickIndicatorScheduler != null) { - mAutoclickIndicatorScheduler.updateCursorAreaSize(size); + mClickScheduler.updateDelay(delay); + } + + if (Flags.enableAutoclickIndicator()) { + if (mAutoclickCursorAreaSizeSettingUri.equals(uri)) { + int size = + Settings.Secure.getIntForUser( + mContentResolver, + Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE, + AUTOCLICK_CURSOR_AREA_SIZE_DEFAULT, + mUserId); + if (mAutoclickIndicatorScheduler != null) { + mAutoclickIndicatorScheduler.updateCursorAreaSize(size); + } + mClickScheduler.updateMovementSlope(size); + } + + if (mAutoclickIgnoreMinorCursorMovementSettingUri.equals(uri)) { + boolean ignoreMinorCursorMovement = + Settings.Secure.getIntForUser( + mContentResolver, + Settings.Secure + .ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT, + AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT_DEFAULT + ? AccessibilityUtils.State.ON + : AccessibilityUtils.State.OFF, + mUserId) + == AccessibilityUtils.State.ON; + mClickScheduler.setIgnoreMinorCursorMovement(ignoreMinorCursorMovement); } } } @@ -365,11 +393,16 @@ public class AutoclickController extends BaseEventStreamTransformation { @VisibleForTesting final class ClickScheduler implements Runnable { /** - * Minimal distance pointer has to move relative to anchor in order for movement not to be - * discarded as noise. Anchor is the position of the last MOVE event that was not considered - * noise. + * Default minimal distance pointer has to move relative to anchor in order for movement not + * to be discarded as noise. Anchor is the position of the last MOVE event that was not + * considered noise. */ - private static final double MOVEMENT_SLOPE = 20f; + private static final double DEFAULT_MOVEMENT_SLOPE = 20f; + + private double mMovementSlope = DEFAULT_MOVEMENT_SLOPE; + + /** Whether the minor cursor movement should be ignored. */ + private boolean mIgnoreMinorCursorMovement = AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT_DEFAULT; /** Whether there is pending click. */ private boolean mActive; @@ -553,7 +586,19 @@ public class AutoclickController extends BaseEventStreamTransformation { float deltaX = mAnchorCoords.x - event.getX(pointerIndex); float deltaY = mAnchorCoords.y - event.getY(pointerIndex); double delta = Math.hypot(deltaX, deltaY); - return delta > MOVEMENT_SLOPE; + double slope = + ((Flags.enableAutoclickIndicator() && mIgnoreMinorCursorMovement) + ? mMovementSlope + : DEFAULT_MOVEMENT_SLOPE); + return delta > slope; + } + + public void setIgnoreMinorCursorMovement(boolean ignoreMinorCursorMovement) { + mIgnoreMinorCursorMovement = ignoreMinorCursorMovement; + } + + private void updateMovementSlope(double slope) { + mMovementSlope = slope; } /** @@ -581,18 +626,30 @@ public class AutoclickController extends BaseEventStreamTransformation { final long now = SystemClock.uptimeMillis(); - MotionEvent downEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 1, - mTempPointerProperties, mTempPointerCoords, mMetaState, - MotionEvent.BUTTON_PRIMARY, 1.0f, 1.0f, mLastMotionEvent.getDeviceId(), 0, - mLastMotionEvent.getSource(), mLastMotionEvent.getFlags()); + MotionEvent downEvent = + MotionEvent.obtain( + /* downTime= */ now, + /* eventTime= */ now, + MotionEvent.ACTION_DOWN, + /* pointerCount= */ 1, + mTempPointerProperties, + mTempPointerCoords, + mMetaState, + BUTTON_PRIMARY, + /* xPrecision= */ 1.0f, + /* yPrecision= */ 1.0f, + mLastMotionEvent.getDeviceId(), + /* edgeFlags= */ 0, + mLastMotionEvent.getSource(), + mLastMotionEvent.getFlags()); MotionEvent pressEvent = MotionEvent.obtain(downEvent); pressEvent.setAction(MotionEvent.ACTION_BUTTON_PRESS); - pressEvent.setActionButton(MotionEvent.BUTTON_PRIMARY); + pressEvent.setActionButton(BUTTON_PRIMARY); MotionEvent releaseEvent = MotionEvent.obtain(downEvent); releaseEvent.setAction(MotionEvent.ACTION_BUTTON_RELEASE); - releaseEvent.setActionButton(MotionEvent.BUTTON_PRIMARY); + releaseEvent.setActionButton(BUTTON_PRIMARY); releaseEvent.setButtonState(0); MotionEvent upEvent = MotionEvent.obtain(downEvent); diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickIndicatorView.java b/services/accessibility/java/com/android/server/accessibility/AutoclickIndicatorView.java index f87dcdb200bb..93ce1f044f0b 100644 --- a/services/accessibility/java/com/android/server/accessibility/AutoclickIndicatorView.java +++ b/services/accessibility/java/com/android/server/accessibility/AutoclickIndicatorView.java @@ -16,15 +16,19 @@ package com.android.server.accessibility; +import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.accessibility.AccessibilityManager.AUTOCLICK_CURSOR_AREA_SIZE_DEFAULT; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.PixelFormat; import android.graphics.RectF; import android.util.DisplayMetrics; import android.view.View; +import android.view.WindowInsets; +import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import android.view.animation.LinearInterpolator; @@ -81,6 +85,26 @@ public class AutoclickIndicatorView extends View { mRingRect = new RectF(); } + /** + * Retrieves the layout params for AutoclickIndicatorView, used when it's added to the Window + * Manager. + */ + public final WindowManager.LayoutParams getLayoutParams() { + final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); + layoutParams.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; + layoutParams.flags = + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; + layoutParams.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; + layoutParams.setFitInsetsTypes(WindowInsets.Type.statusBars()); + layoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + layoutParams.format = PixelFormat.TRANSLUCENT; + layoutParams.setTitle(AutoclickIndicatorView.class.getSimpleName()); + layoutParams.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; + return layoutParams; + } + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java index bf9202f1b266..5c0bbf4e01eb 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java @@ -31,6 +31,7 @@ import android.view.accessibility.AccessibilityManager; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.accessibility.EventStreamTransformation; +import com.android.server.accessibility.Flags; import com.android.server.policy.WindowManagerPolicy; /** @@ -297,7 +298,8 @@ class EventDispatcher { sendMotionEvent( prototype, action, - mState.getLastReceivedEvent(), + Flags.eventDispatcherRawEvent() ? mState.getLastReceivedRawEvent() : + mState.getLastReceivedEvent(), pointerIdBits, policyFlags); } @@ -327,7 +329,8 @@ class EventDispatcher { sendMotionEvent( event, action, - mState.getLastReceivedEvent(), + Flags.eventDispatcherRawEvent() ? mState.getLastReceivedRawEvent() : + mState.getLastReceivedEvent(), pointerIdBits, policyFlags); } @@ -394,8 +397,10 @@ class EventDispatcher { continue; } final int action = computeInjectionAction(MotionEvent.ACTION_POINTER_UP, i); - sendMotionEvent( - prototype, action, mState.getLastReceivedEvent(), pointerIdBits, policyFlags); + sendMotionEvent(prototype, action, + Flags.eventDispatcherRawEvent() ? mState.getLastReceivedRawEvent() : + mState.getLastReceivedEvent(), + pointerIdBits, policyFlags); pointerIdBits &= ~(1 << pointerId); } } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 2c106d31ae59..fd230f69aec0 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -497,13 +497,14 @@ public class TouchExplorer extends BaseEventStreamTransformation // We have just decided that the user is touch, // exploring so start sending events. - mSendHoverEnterAndMoveDelayed.addEvent(event, mState.getLastReceivedEvent()); + mSendHoverEnterAndMoveDelayed.addEvent(event, + Flags.eventDispatcherRawEvent() ? rawEvent : mState.getLastReceivedEvent()); mSendHoverEnterAndMoveDelayed.forceSendAndRemove(); mSendHoverExitDelayed.cancel(); mDispatcher.sendMotionEvent( event, ACTION_HOVER_MOVE, - event, + Flags.eventDispatcherRawEvent() ? rawEvent : event, pointerIdBits, policyFlags); return true; @@ -1099,7 +1100,8 @@ public class TouchExplorer extends BaseEventStreamTransformation * * @param policyFlags The policy flags associated with the event. */ - private void sendHoverExitAndTouchExplorationGestureEndIfNeeded(int policyFlags) { + @VisibleForTesting + void sendHoverExitAndTouchExplorationGestureEndIfNeeded(int policyFlags) { MotionEvent event = mState.getLastInjectedHoverEvent(); if (event != null && event.getActionMasked() != ACTION_HOVER_EXIT) { final int pointerIdBits = event.getPointerIdBits(); @@ -1109,7 +1111,8 @@ public class TouchExplorer extends BaseEventStreamTransformation mDispatcher.sendMotionEvent( event, ACTION_HOVER_EXIT, - mState.getLastReceivedEvent(), + Flags.eventDispatcherRawEvent() ? mState.getLastReceivedRawEvent() : + mState.getLastReceivedEvent(), pointerIdBits, policyFlags); } @@ -1131,7 +1134,8 @@ public class TouchExplorer extends BaseEventStreamTransformation mDispatcher.sendMotionEvent( event, ACTION_HOVER_ENTER, - mState.getLastReceivedEvent(), + Flags.eventDispatcherRawEvent() ? mState.getLastReceivedRawEvent() : + mState.getLastReceivedEvent(), pointerIdBits, policyFlags); } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index c68e54956c99..25494fce9fbf 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -19,6 +19,7 @@ package com.android.server.autofill; import static android.Manifest.permission.MANAGE_AUTO_FILL; import static android.content.Context.AUTOFILL_MANAGER_SERVICE; import static android.service.autofill.Flags.fixGetAutofillComponent; +import static android.service.autofill.Flags.improveFillDialogAconfig; import static android.view.autofill.AutofillManager.MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS; import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString; @@ -70,6 +71,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.TimeUtils; +import android.view.InsetsController; import android.view.autofill.AutofillFeatureFlags; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; @@ -96,6 +98,7 @@ import com.android.server.autofill.ui.AutoFillUI; import com.android.server.infra.AbstractMasterSystemService; import com.android.server.infra.FrameworkResourcesServiceNameResolver; import com.android.server.infra.SecureSettingsServiceNameResolver; +import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -243,6 +246,8 @@ public final class AutofillManagerService private static final boolean DEFAULT_PCC_USE_FALLBACK = true; + private static final boolean DBG = false; + public AutofillManagerService(Context context) { super(context, new SecureSettingsServiceNameResolver(context, Settings.Secure.AUTOFILL_SERVICE), @@ -301,8 +306,79 @@ public final class AutofillManagerService mCredentialAutofillService = null; Slog.w(TAG, "Invalid CredentialAutofillService"); } + + if (improveFillDialogAconfig()) { + WindowManagerInternal windowManagerInternal = LocalServices.getService( + WindowManagerInternal.class); + WindowManagerInternal.ImeInsetsAnimationChangeListener + imeInsetsAnimationChangeListener = + new WindowManagerInternal.ImeInsetsAnimationChangeListener() { + @Override + public void onAnimationStart( + @InsetsController.AnimationType int animationType, int userId) { + if (DBG) { + Slog.e(TAG, + "onAnimationStart() notifyImeAnimationStart() " + + "animationType:" + + String.valueOf(animationType)); + } + synchronized (mLock) { + + // We are mostly interested in animations that show up the IME + if (animationType == InsetsController.ANIMATION_TYPE_HIDE) { + // IME is going away + mIsImeShowing = false; + } + if (animationType != InsetsController.ANIMATION_TYPE_SHOW) { + return; + } + mIsImeShowing = true; + mImeAnimatingWhileShowingUp = true; + final AutofillManagerServiceImpl service = + peekServiceForUserWithLocalBinderIdentityLocked(userId); + if (service != null) { + service.notifyImeAnimationStart(); + } else if (sVerbose) { + Slog.v(TAG, + "notifyImeAnimationStart(): no service for " + userId); + } + } + } + + @Override + public void onAnimationEnd( + @InsetsController.AnimationType int animationType, int userId) { + if (DBG) { + Slog.e(TAG, + "onAnimationEnd() notifyImeAnimationEnd() " + + "animationType:" + + String.valueOf(animationType)); + } + // We are only interested in animations that show up the IME + if (animationType != InsetsController.ANIMATION_TYPE_SHOW) { + return; + } + mImeAnimatingWhileShowingUp = false; + synchronized (mLock) { + final AutofillManagerServiceImpl service = + peekServiceForUserWithLocalBinderIdentityLocked(userId); + if (service != null) { + service.notifyImeAnimationEnd(); + } else if (sVerbose) { + Slog.v(TAG, "notifyImeAnimationEnd(): no service for " + + userId); + } + } + } + }; + windowManagerInternal.setImeInsetsAnimationChangeListener( + imeInsetsAnimationChangeListener); + } } + public boolean mImeAnimatingWhileShowingUp = false; + public boolean mIsImeShowing = false; + @Override // from AbstractMasterSystemService protected String getServiceSettingsProperty() { return Settings.Secure.AUTOFILL_SERVICE; diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 11710c9d8a9b..eda62334ff39 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -73,6 +73,7 @@ import android.util.LocalLog; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.view.autofill.AutofillFeatureFlags; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillManager.AutofillCommitReason; @@ -208,6 +209,11 @@ final class AutofillManagerServiceImpl private final DisabledInfoCache mDisabledInfoCache; + // Tracks active session id. There is no guarantee that such a session exists. For eg, if the + // session is destroyed, the id may no longer be valid. We don't update the state in all the + // cases. + private int mActiveSessionId = NO_SESSION; + AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui, AutofillCompatState autofillCompatState, @@ -386,6 +392,7 @@ final class AutofillManagerServiceImpl @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback, @NonNull ComponentName clientActivity, boolean compatMode, boolean bindInstantServiceAllowed, int flags) { + mActiveSessionId = NO_SESSION; // FLAG_AUGMENTED_AUTOFILL_REQUEST is set in the flags when standard autofill is disabled // but the package is allowlisted for augmented autofill boolean forAugmentedAutofillOnly = (flags @@ -444,6 +451,7 @@ final class AutofillManagerServiceImpl if (newSession == null) { return NO_SESSION; } + mActiveSessionId = newSession.id; // Service can be null when it's only for augmented autofill String servicePackageName = mInfo == null ? null : mInfo.getServiceInfo().packageName; @@ -672,7 +680,7 @@ final class AutofillManagerServiceImpl flags, mInputMethodManagerInternal, isPrimaryCredential); mSessions.put(newSession.id, newSession); - if (Flags.multipleFillHistory() && !forAugmentedAutofillOnly) { + if (AutofillFeatureFlags.isMultipleFillEventHistoryEnabled() && !forAugmentedAutofillOnly) { mFillHistories.put(newSession.id, new FillEventHistory(sessionId, null)); } @@ -747,6 +755,7 @@ final class AutofillManagerServiceImpl Slog.d(TAG, "restarting session " + sessionId + " due to manual request on " + autofillId); } + mActiveSessionId = sessionId; return true; } if (sVerbose) { @@ -756,6 +765,8 @@ final class AutofillManagerServiceImpl return false; } + + mActiveSessionId = sessionId; session.updateLocked(autofillId, virtualBounds, value, action, flags); return false; } @@ -772,7 +783,8 @@ final class AutofillManagerServiceImpl FillEventHistory history = null; - if (Flags.multipleFillHistory() && mFillHistories != null) { + if (AutofillFeatureFlags.isMultipleFillEventHistoryEnabled() + && mFillHistories != null) { history = mFillHistories.get(sessionId); mFillHistories.delete(sessionId); } @@ -874,21 +886,54 @@ final class AutofillManagerServiceImpl } @GuardedBy("mLock") + public void notifyImeAnimationStart() { + if (!isEnabledLocked()) { + Slog.wtf(TAG, "Service not enabled"); + return; + } + final Session session = mSessions.get(mActiveSessionId); + if (session == null) { + Slog.v(TAG, "notifyImeAnimationEnd(): no session for " + mActiveSessionId); + return; + } + session.notifyImeAnimationStart(SystemClock.elapsedRealtime()); + } + + @GuardedBy("mLock") public void notifyImeAnimationEnd(int sessionId, long endTimeMs, int uid) { if (!isEnabledLocked()) { Slog.wtf(TAG, "Service not enabled"); return; } final Session session = mSessions.get(sessionId); - if (session == null || uid != session.uid) { + if (session == null) { Slog.v(TAG, "notifyImeAnimationEnd(): no session for " + sessionId + "(" + uid + ")"); return; } + if (uid != session.uid) { + Slog.v(TAG, "notifyImeAnimationEnd(): Mismatched session id's " + + sessionId + "(" + uid + ")"); + return; + } session.notifyImeAnimationEnd(endTimeMs); } @GuardedBy("mLock") + public void notifyImeAnimationEnd() { + if (!isEnabledLocked()) { + Slog.wtf(TAG, "Service not enabled"); + return; + } + final Session session = mSessions.get(mActiveSessionId); + if (session == null) { + Slog.v(TAG, "notifyImeAnimationEnd(): no session for " + mActiveSessionId); + return; + } + session.notifyImeAnimationEnd(SystemClock.elapsedRealtime()); + } + + @GuardedBy("mLock") @Override // from PerUserSystemService protected void handlePackageUpdateLocked(@NonNull String packageName) { final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo(); @@ -922,7 +967,7 @@ final class AutofillManagerServiceImpl } } mSessions.clear(); - if (Flags.multipleFillHistory()) { + if (AutofillFeatureFlags.isMultipleFillEventHistoryEnabled()) { mFillHistories.clear(); } @@ -991,7 +1036,7 @@ final class AutofillManagerServiceImpl mEventHistory.addEvent(event); } - if (Flags.multipleFillHistory()) { + if (AutofillFeatureFlags.isMultipleFillEventHistoryEnabled()) { FillEventHistory history = mFillHistories.get(sessionId); if (history != null) { history.addEvent(event); @@ -1180,7 +1225,7 @@ final class AutofillManagerServiceImpl logViewEnteredForHistory(sessionId, clientState, mEventHistory, focusedId); } - if (Flags.multipleFillHistory()) { + if (AutofillFeatureFlags.isMultipleFillEventHistoryEnabled()) { FillEventHistory history = mFillHistories.get(sessionId); if (history != null) { logViewEnteredForHistory(sessionId, clientState, history, focusedId); diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 3ecff3b3ebae..6fdb2b6b83f7 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -442,6 +442,9 @@ final class Session private Bundle mClientState; @GuardedBy("mLock") + private Bundle mClientStateForSecondary; + + @GuardedBy("mLock") boolean mDestroyed; /** @@ -980,13 +983,19 @@ final class Session mergePreviousSessionLocked(/* forSave= */ false); final List<String> hints = getTypeHintsForProvider(); + Bundle sendBackClientState = mClientState; + if (Flags.multipleFillHistory() + && mRequestId.isSecondaryProvider(requestId)) { + sendBackClientState = mClientStateForSecondary; + } + mDelayedFillPendingIntent = createPendingIntent(requestId); request = new FillRequest( requestId, contexts, hints, - mClientState, + sendBackClientState, flags, /* inlineSuggestionsRequest= */ null, /* delayedFillIntentSender= */ mDelayedFillPendingIntent == null @@ -3317,7 +3326,7 @@ final class Session AUTHENTICATION_RESULT_SUCCESS); if (newClientState != null) { if (sDebug) Slog.d(TAG, "Updating client state from auth dataset"); - mClientState = newClientState; + setClientState(newClientState, requestId); } Dataset datasetFromResult = getEffectiveDatasetForAuthentication((Dataset) result); final Dataset oldDataset = authenticatedResponse.getDatasets().get(datasetIdx); @@ -6700,6 +6709,18 @@ final class Session } @GuardedBy("mLock") + private void setClientState(@Nullable Bundle newClientState, int requestId) { + if (Flags.multipleFillHistory() + && mRequestId.isSecondaryProvider(requestId)) { + // Set the secondary clientstate + mClientStateForSecondary = newClientState; + } else { + // The old way - only set the primary provider clientstate + mClientState = newClientState; + } + } + + @GuardedBy("mLock") private void processResponseLocked( @NonNull FillResponse newResponse, @Nullable Bundle newClientState, int flags) { // Make sure we are hiding the UI which will be shown @@ -6734,7 +6755,9 @@ final class Session mResponses = new SparseArray<>(2); } mResponses.put(requestId, newResponse); - mClientState = newClientState != null ? newClientState : newResponse.getClientState(); + + setClientState(newClientState != null ? newClientState : newResponse.getClientState(), + requestId); boolean webviewRequestedCredman = newClientState != null diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index a54a66312b1d..5184a2c4ec30 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -111,6 +111,7 @@ public class SettingsToPropertiesMapper { DeviceConfig.NAMESPACE_LMKD_NATIVE, DeviceConfig.NAMESPACE_MEDIA_NATIVE, DeviceConfig.NAMESPACE_MGLRU_NATIVE, + DeviceConfig.NAMESPACE_MMD_NATIVE, DeviceConfig.NAMESPACE_NETD_NATIVE, DeviceConfig.NAMESPACE_NNAPI_NATIVE, DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 12b666fc458a..709c13bc9704 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -68,6 +68,7 @@ import static com.android.media.audio.Flags.alarmMinVolumeZero; import static com.android.media.audio.Flags.asDeviceConnectionFailure; import static com.android.media.audio.Flags.audioserverPermissions; import static com.android.media.audio.Flags.disablePrescaleAbsoluteVolume; +import static com.android.media.audio.Flags.deferWearPermissionUpdates; import static com.android.media.audio.Flags.equalScoLeaVcIndexRange; import static com.android.media.audio.Flags.replaceStreamBtSco; import static com.android.media.audio.Flags.ringMyCar; @@ -514,6 +515,15 @@ public class AudioService extends IAudioService.Stub // check playback or record activity every 6 seconds for UIDs owning mode IN_COMMUNICATION private static final int CHECK_MODE_FOR_UID_PERIOD_MS = 6000; + // Roughly chosen to be long enough to suppress the autocork behavior of the permission + // cache (50ms), while not introducing visible permission leaks - since the app needs to + // restart, and trigger an action which requires permissions from audioserver before this + // delay. For RECORD_AUDIO, we are additionally protected by appops. + private static final int SCHEDULED_PERMISSION_UPDATE_DELAY_MS = 60; + + // Increased delay to not interefere with low core app launch latency + private static final int SCHEDULED_PERMISSION_UPDATE_LONG_DELAY_MS = 500; + /** @see AudioSystemThread */ private AudioSystemThread mAudioSystemThread; /** @see AudioHandler */ @@ -10975,12 +10985,7 @@ public class AudioService extends IAudioService.Stub } /* Listen to permission invalidations for the PermissionProvider */ - private void setupPermissionListener() { - // Roughly chosen to be long enough to suppress the autocork behavior of the permission - // cache (50ms), while not introducing visible permission leaks - since the app needs to - // restart, and trigger an action which requires permissions from audioserver before this - // delay. For RECORD_AUDIO, we are additionally protected by appops. - final long UPDATE_DELAY_MS = 60; + private void setupPermissionListener() { // instanceof to simplify the construction requirements of AudioService for testing: no // delayed execution during unit tests. if (mAudioServerLifecycleExecutor instanceof ScheduledExecutorService exec) { @@ -11022,7 +11027,7 @@ public class AudioService extends IAudioService.Stub Thread.getDefaultUncaughtExceptionHandler() .uncaughtException(Thread.currentThread(), e); } - }, UPDATE_DELAY_MS, TimeUnit.MILLISECONDS)); + }, getAudioPermissionsDelay(), TimeUnit.MILLISECONDS)); } }; mSysPropListenerNativeHandle = mAudioSystem.listenForSystemPropertyChange( @@ -13029,10 +13034,10 @@ public class AudioService extends IAudioService.Stub int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID); if (intent.getBooleanExtra(EXTRA_REPLACING, false) || intent.getBooleanExtra(EXTRA_ARCHIVAL, false)) return; - if (action.equals(ACTION_PACKAGE_ADDED)) { + if (ACTION_PACKAGE_ADDED.equals(action)) { audioserverExecutor.execute(() -> provider.onModifyPackageState(uid, pkgName, false /* isRemoved */)); - } else if (action.equals(ACTION_PACKAGE_REMOVED)) { + } else if (ACTION_PACKAGE_REMOVED.equals(action)) { audioserverExecutor.execute(() -> provider.onModifyPackageState(uid, pkgName, true /* isRemoved */)); } @@ -15513,6 +15518,18 @@ public class AudioService extends IAudioService.Stub } } + private long getAudioPermissionsDelay() { + return isAudioPermissionUpdatesAddtionallyDelayed() + ? SCHEDULED_PERMISSION_UPDATE_LONG_DELAY_MS + : SCHEDULED_PERMISSION_UPDATE_DELAY_MS; + } + + private boolean isAudioPermissionUpdatesAddtionallyDelayed() { + // Additional delays on low core devices in order to optimize app launch latencies + return deferWearPermissionUpdates() + && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); + } + //==================== // Helper functions for app ops //==================== diff --git a/services/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java index f66c7e115fc0..677e0c055455 100644 --- a/services/core/java/com/android/server/backup/SystemBackupAgent.java +++ b/services/core/java/com/android/server/backup/SystemBackupAgent.java @@ -35,7 +35,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; -import com.android.server.backup.Flags; +import com.android.server.display.DisplayBackupHelper; import com.android.server.notification.NotificationBackupHelper; import com.google.android.collect.Sets; @@ -67,6 +67,7 @@ public class SystemBackupAgent extends BackupAgentHelper { private static final String APP_GENDER_HELPER = "app_gender"; private static final String COMPANION_HELPER = "companion"; private static final String SYSTEM_GENDER_HELPER = "system_gender"; + private static final String DISPLAY_HELPER = "display"; // These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME // are also used in the full-backup file format, so must not change unless steps are @@ -104,7 +105,8 @@ public class SystemBackupAgent extends BackupAgentHelper { APP_LOCALES_HELPER, COMPANION_HELPER, APP_GENDER_HELPER, - SYSTEM_GENDER_HELPER); + SYSTEM_GENDER_HELPER, + DISPLAY_HELPER); /** Helpers that are enabled for full, non-system users. */ private static final Set<String> sEligibleHelpersForNonSystemUser = @@ -146,6 +148,7 @@ public class SystemBackupAgent extends BackupAgentHelper { addHelperIfEligibleForUser(COMPANION_HELPER, new CompanionBackupHelper(mUserId)); addHelperIfEligibleForUser(SYSTEM_GENDER_HELPER, new SystemGrammaticalGenderBackupHelper(mUserId)); + addHelperIfEligibleForUser(DISPLAY_HELPER, new DisplayBackupHelper(mUserId)); } @Override diff --git a/services/core/java/com/android/server/display/DisplayBackupHelper.java b/services/core/java/com/android/server/display/DisplayBackupHelper.java new file mode 100644 index 000000000000..0d3a09fb2305 --- /dev/null +++ b/services/core/java/com/android/server/display/DisplayBackupHelper.java @@ -0,0 +1,137 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + + +import android.annotation.Nullable; +import android.app.backup.BlobBackupHelper; +import android.hardware.display.DisplayManagerInternal; +import android.util.AtomicFile; +import android.util.AtomicFileOutputStream; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; +import com.android.server.display.feature.DisplayManagerFlags; +import com.android.server.display.utils.DebugUtils; + +import java.io.IOException; + +/** + * Display manager specific information backup helper. Backs-up the entire files for the given + * user. + * @hide + */ +public class DisplayBackupHelper extends BlobBackupHelper { + private static final String TAG = "DisplayBackupHelper"; + + // current schema of the backup state blob + private static final int BLOB_VERSION = 1; + + // key under which the data blob is committed to back up + private static final String KEY_DISPLAY = "display"; + + // To enable these logs, run: + // adb shell setprop persist.log.tag.DisplayBackupHelper DEBUG + // adb reboot + private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); + + private final int mUserId; + private final Injector mInjector; + + /** + * Construct a helper to manage backup/restore of entire files within Display Manager. + * + * @param userId id of the user for which backup will be done. + */ + public DisplayBackupHelper(int userId) { + this(userId, new Injector()); + } + + @VisibleForTesting + DisplayBackupHelper(int userId, Injector injector) { + super(BLOB_VERSION, KEY_DISPLAY); + mUserId = userId; + mInjector = injector; + } + + @Override + protected byte[] getBackupPayload(String key) { + if (!KEY_DISPLAY.equals(key) || !mInjector.isDisplayTopologyFlagEnabled()) { + return null; + } + try { + var result = mInjector.readTopologyFile(mUserId); + Slog.i(TAG, "getBackupPayload for " + key + " done, size=" + result.length); + return result; + } catch (IOException e) { + if (DEBUG) Slog.d(TAG, "Skip topology backup", e); + return null; + } + } + + @Override + protected void applyRestoredPayload(String key, byte[] payload) { + if (!KEY_DISPLAY.equals(key) || !mInjector.isDisplayTopologyFlagEnabled()) { + return; + } + try (var oStream = mInjector.writeTopologyFile(mUserId)) { + oStream.write(payload); + oStream.markSuccess(); + Slog.i(TAG, "applyRestoredPayload for " + key + " size=" + payload.length + + " to " + oStream); + } catch (IOException e) { + Slog.e(TAG, "applyRestoredPayload failed", e); + return; + } + var displayManagerInternal = mInjector.getDisplayManagerInternal(); + if (displayManagerInternal == null) { + Slog.e(TAG, "DisplayManagerInternal is null"); + return; + } + + displayManagerInternal.reloadTopologies(mUserId); + } + + @VisibleForTesting + static class Injector { + private final boolean mIsDisplayTopologyEnabled = + new DisplayManagerFlags().isDisplayTopologyEnabled(); + + boolean isDisplayTopologyFlagEnabled() { + return mIsDisplayTopologyEnabled; + } + + @Nullable + DisplayManagerInternal getDisplayManagerInternal() { + return LocalServices.getService(DisplayManagerInternal.class); + } + + byte[] readTopologyFile(int userId) throws IOException { + return getTopologyFile(userId).readFully(); + } + + AtomicFileOutputStream writeTopologyFile(int userId) throws IOException { + return new AtomicFileOutputStream(getTopologyFile(userId)); + } + + private AtomicFile getTopologyFile(int userId) { + return new AtomicFile(DisplayTopologyXmlStore.getUserTopologyFile(userId), + /*commitTag=*/ "topology-state"); + } + }; +} diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 3598b9b2e879..49b451a83efa 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -37,10 +37,12 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_S import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; import static android.hardware.display.DisplayManagerGlobal.DisplayEvent; import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL; @@ -70,6 +72,7 @@ import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; +import android.app.backup.BackupManager; import android.app.compat.CompatChanges; import android.companion.virtual.IVirtualDevice; import android.companion.virtual.VirtualDeviceManager; @@ -676,9 +679,10 @@ public final class DisplayManagerService extends SystemService { mExternalDisplayStatsService); mExternalDisplayPolicy = new ExternalDisplayPolicy(new ExternalDisplayPolicyInjector()); if (mFlags.isDisplayTopologyEnabled()) { - mDisplayTopologyCoordinator = - new DisplayTopologyCoordinator(this::isExtendedDisplayEnabled, - this::deliverTopologyUpdate, new HandlerExecutor(mHandler), mSyncRoot); + final var backupManager = new BackupManager(mContext); + mDisplayTopologyCoordinator = new DisplayTopologyCoordinator( + this::isExtendedDisplayEnabled, this::deliverTopologyUpdate, + new HandlerExecutor(mHandler), mSyncRoot, backupManager::dataChanged); } else { mDisplayTopologyCoordinator = null; } @@ -758,6 +762,11 @@ public final class DisplayManagerService extends SystemService { } @Override + public void onUserUnlocked(@NonNull final TargetUser to) { + scheduleTopologiesReload(to.getUserIdentifier(), /*isUserSwitching=*/ true); + } + + @Override public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { final int newUserId = to.getUserIdentifier(); final int userSerial = getUserManager().getUserSerialNumber(newUserId); @@ -796,6 +805,11 @@ public final class DisplayManagerService extends SystemService { if (mFlags.isDisplayContentModeManagementEnabled()) { updateMirrorBuiltInDisplaySettingLocked(); } + + final UserManager userManager = getUserManager(); + if (null != userManager && userManager.isUserUnlockingOrUnlocked(mCurrentUserId)) { + scheduleTopologiesReload(mCurrentUserId, /*isUserSwitching=*/ true); + } } } @@ -873,6 +887,8 @@ public final class DisplayManagerService extends SystemService { mSmallAreaDetectionController = (mFlags.isSmallAreaDetectionEnabled()) ? SmallAreaDetectionController.create(mContext) : null; + + scheduleTopologiesReload(mCurrentUserId, /*isUserSwitching=*/ false); } @VisibleForTesting @@ -925,6 +941,15 @@ public final class DisplayManagerService extends SystemService { return mDisplayNotificationManager; } + private void scheduleTopologiesReload(final int userId, final boolean isUserSwitching) { + if (mDisplayTopologyCoordinator != null) { + // Need background thread due to xml files read operations not allowed on Display thread + BackgroundThread.getHandler().post(() -> + mDisplayTopologyCoordinator.reloadTopologies( + userId, isUserSwitching)); + } + } + private void loadStableDisplayValuesLocked() { final Point size = mPersistentDataStore.getStableDisplaySize(); if (size.x > 0 && size.y > 0) { @@ -1800,7 +1825,11 @@ public final class DisplayManagerService extends SystemService { } if ((flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) { - flags |= VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; + if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) == 0) { + Slog.d(TAG, "Public virtual displays are auto mirror by default, hence adding " + + "VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR."); + flags |= VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; + } // Public displays can't be allowed to show content when locked. if ((flags & VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) { @@ -1808,10 +1837,16 @@ public final class DisplayManagerService extends SystemService { "Public display must not be marked as SHOW_WHEN_LOCKED_INSECURE"); } } - if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) { + if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0 + && (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { + Slog.d(TAG, "Own content displays cannot auto mirror other displays, hence ignoring " + + "VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR."); flags &= ~VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; } - if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { + if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0 + && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { + Slog.d(TAG, "Auto mirror displays must be in the default display group, hence ignoring " + + "VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP."); flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; } // Put the display in the virtual device's display group only if it's not a mirror display, @@ -1821,6 +1856,8 @@ public final class DisplayManagerService extends SystemService { && (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0 && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == VIRTUAL_DISPLAY_FLAG_TRUSTED && virtualDevice != null) { + Slog.d(TAG, "Own content displays owned by virtual devices are put in that device's " + + "display group, hence adding VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP."); flags |= VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP; } @@ -1852,8 +1889,7 @@ public final class DisplayManagerService extends SystemService { Binder.restoreCallingIdentity(firstToken); } - if (callingUid != Process.SYSTEM_UID - && (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { + if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { // Only a valid media projection or a virtual device can create a mirror virtual // display. if (!canProjectVideo(projection) && !canCreateMirrorDisplays(virtualDevice) @@ -1901,6 +1937,14 @@ public final class DisplayManagerService extends SystemService { } } + if ((flags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0 + && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) == 0 + && (flags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) == 0) { + Slog.d(TAG, "Always unlocked displays cannot be in the default display group, hence " + + "ignoring flag VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED."); + flags &= ~VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; + } + if ((flags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0) { if (callingUid != Process.SYSTEM_UID && !checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY, @@ -1911,7 +1955,24 @@ public final class DisplayManagerService extends SystemService { } } - if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { + if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_FOCUS) != 0 + && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { + Slog.d(TAG, "Untrusted displays cannot have own focus, hence ignoring flag " + + "VIRTUAL_DISPLAY_FLAG_OWN_FOCUS."); + flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_FOCUS; + } + + if ((flags & VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED) != 0 + && (flags & VIRTUAL_DISPLAY_FLAG_OWN_FOCUS) == 0) { + Slog.d(TAG, "Virtual displays that cannot steal top focus must have their own " + + " focus, hence ignoring flag VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED."); + flags &= ~VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED; + } + + if ((flags & VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0 + && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { + Slog.d(TAG, "Untrusted displays cannot show system decorations, hence ignoring flag " + + "VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS."); flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } @@ -4157,7 +4218,8 @@ public final class DisplayManagerService extends SystemService { public boolean shouldReceiveRefreshRateWithChangeUpdate(int event) { if (mFlags.isRefreshRateEventForForegroundAppsEnabled() - && event == DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED) { + && event == DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED + && mActivityManagerInternal != null) { int procState = mActivityManagerInternal.getUidProcessState(mUid); int importance = ActivityManager.RunningAppProcessInfo .procStateToImportance(procState); @@ -5937,6 +5999,14 @@ public final class DisplayManagerService extends SystemService { public boolean isDisplayReadyForMirroring(int displayId) { return mExternalDisplayPolicy.isDisplayReadyForMirroring(displayId); } + + @Override + public void reloadTopologies(final int userId) { + // Reload topologies only if the userId matches the current user id. + if (userId == mCurrentUserId) { + scheduleTopologiesReload(mCurrentUserId, /*isUserSwitching=*/ false); + } + } } class DesiredDisplayModeSpecsObserver diff --git a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java index 88650394020b..c73ab32f117a 100644 --- a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java +++ b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java @@ -19,6 +19,8 @@ package com.android.server.display; import static android.hardware.display.DisplayTopology.pxToDp; import android.hardware.display.DisplayTopology; +import android.util.Slog; +import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; @@ -26,6 +28,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.Executor; import java.util.function.BooleanSupplier; import java.util.function.Consumer; @@ -35,9 +39,25 @@ import java.util.function.Consumer; * persisting the topology. */ class DisplayTopologyCoordinator { + private static final String TAG = "DisplayTopologyCoordinator"; + + private static String getUniqueId(DisplayInfo info) { + if (info.displayId == Display.DEFAULT_DISPLAY && info.type == Display.TYPE_INTERNAL) { + return "internal"; + } + return info.uniqueId; + } + + // Persistent data store for display topologies. + private final DisplayTopologyStore mTopologyStore; @GuardedBy("mSyncRoot") private DisplayTopology mTopology; + @GuardedBy("mSyncRoot") + private final Map<String, Integer> mUniqueIdToDisplayIdMapping = new HashMap<>(); + + @GuardedBy("mSyncRoot") + private final SparseArray<String> mDisplayIdToUniqueIdMapping = new SparseArray<>(); /** * Check if extended displays are enabled. If not, a topology is not needed. @@ -52,23 +72,29 @@ class DisplayTopologyCoordinator { private final Consumer<DisplayTopology> mOnTopologyChangedCallback; private final Executor mTopologyChangeExecutor; private final DisplayManagerService.SyncRoot mSyncRoot; + private final Runnable mTopologySavedCallback; DisplayTopologyCoordinator(BooleanSupplier isExtendedDisplayEnabled, Consumer<DisplayTopology> onTopologyChangedCallback, - Executor topologyChangeExecutor, DisplayManagerService.SyncRoot syncRoot) { + Executor topologyChangeExecutor, DisplayManagerService.SyncRoot syncRoot, + Runnable topologySavedCallback) { this(new Injector(), isExtendedDisplayEnabled, onTopologyChangedCallback, - topologyChangeExecutor, syncRoot); + topologyChangeExecutor, syncRoot, topologySavedCallback); } @VisibleForTesting DisplayTopologyCoordinator(Injector injector, BooleanSupplier isExtendedDisplayEnabled, Consumer<DisplayTopology> onTopologyChangedCallback, - Executor topologyChangeExecutor, DisplayManagerService.SyncRoot syncRoot) { + Executor topologyChangeExecutor, DisplayManagerService.SyncRoot syncRoot, + Runnable topologySavedCallback) { mTopology = injector.getTopology(); mIsExtendedDisplayEnabled = isExtendedDisplayEnabled; mOnTopologyChangedCallback = onTopologyChangedCallback; mTopologyChangeExecutor = topologyChangeExecutor; mSyncRoot = syncRoot; + mTopologyStore = injector.createTopologyStore( + mDisplayIdToUniqueIdMapping, mUniqueIdToDisplayIdMapping); + mTopologySavedCallback = topologySavedCallback; } /** @@ -80,7 +106,10 @@ class DisplayTopologyCoordinator { return; } synchronized (mSyncRoot) { + addDisplayIdMappingLocked(info); + mTopology.addDisplay(info.displayId, getWidth(info), getHeight(info)); + restoreTopologyLocked(); sendTopologyUpdateLocked(); } } @@ -104,12 +133,40 @@ class DisplayTopologyCoordinator { void onDisplayRemoved(int displayId) { synchronized (mSyncRoot) { if (mTopology.removeDisplay(displayId)) { + removeDisplayIdMappingLocked(displayId); + restoreTopologyLocked(); sendTopologyUpdateLocked(); } } } /** + * Loads all topologies from the persistent topology store for the given userId. + * @param userId the user id, same as returned from + * {@link android.app.ActivityManagerInternal#getCurrentUserId()}. + * @param isUserSwitching whether the id of the user is currently switching. + */ + void reloadTopologies(int userId, boolean isUserSwitching) { + boolean isTopologySaved = false; + synchronized (mSyncRoot) { + mTopologyStore.reloadTopologies(userId); + boolean isTopologyRestored = restoreTopologyLocked(); + if (isTopologyRestored) { + sendTopologyUpdateLocked(); + } + if (isUserSwitching && !isTopologyRestored) { + // During user switch, if topology is not restored - last user topology is the + // good initial guess. Save this topology for consistent use in the future. + isTopologySaved = mTopologyStore.saveTopology(mTopology); + } + } + + if (isTopologySaved) { + mTopologySavedCallback.run(); + } + } + + /** * @return A deep copy of the topology. */ DisplayTopology getTopology() { @@ -119,10 +176,16 @@ class DisplayTopologyCoordinator { } void setTopology(DisplayTopology topology) { + final boolean isTopologySaved; synchronized (mSyncRoot) { + topology.normalize(); mTopology = topology; - mTopology.normalize(); sendTopologyUpdateLocked(); + isTopologySaved = mTopologyStore.saveTopology(topology); + } + + if (isTopologySaved) { + mTopologySavedCallback.run(); } } @@ -136,6 +199,24 @@ class DisplayTopologyCoordinator { } } + @GuardedBy("mSyncRoot") + private void removeDisplayIdMappingLocked(final int displayId) { + final String uniqueId = mDisplayIdToUniqueIdMapping.get(displayId); + if (null == uniqueId) { + Slog.e(TAG, "Can't find uniqueId for displayId=" + displayId); + return; + } + mDisplayIdToUniqueIdMapping.remove(displayId); + mUniqueIdToDisplayIdMapping.remove(uniqueId); + } + + @GuardedBy("mSyncRoot") + private void addDisplayIdMappingLocked(DisplayInfo info) { + final String uniqueId = getUniqueId(info); + mUniqueIdToDisplayIdMapping.put(uniqueId, info.displayId); + mDisplayIdToUniqueIdMapping.put(info.displayId, uniqueId); + } + /** * @param info The display info * @return The width of the display in dp @@ -157,6 +238,21 @@ class DisplayTopologyCoordinator { && info.displayGroupId == Display.DEFAULT_DISPLAY_GROUP; } + /** + * Restores {@link #mTopology} from {@link #mTopologyStore}, saves it in {@link #mTopology}. + * @return true if the topology was restored, false otherwise. + */ + @GuardedBy("mSyncRoot") + private boolean restoreTopologyLocked() { + var restoredTopology = mTopologyStore.restoreTopology(mTopology); + if (restoredTopology == null) { + return false; + } + mTopology = restoredTopology; + mTopology.normalize(); + return true; + } + @GuardedBy("mSyncRoot") private void sendTopologyUpdateLocked() { DisplayTopology copy = mTopology.copy(); @@ -168,5 +264,21 @@ class DisplayTopologyCoordinator { DisplayTopology getTopology() { return new DisplayTopology(); } + + DisplayTopologyStore createTopologyStore( + SparseArray<String> displayIdToUniqueIdMapping, + Map<String, Integer> uniqueIdToDisplayIdMapping) { + return new DisplayTopologyXmlStore(new DisplayTopologyXmlStore.Injector() { + @Override + public SparseArray<String> getDisplayIdToUniqueIdMapping() { + return displayIdToUniqueIdMapping; + } + + @Override + public Map<String, Integer> getUniqueIdToDisplayIdMapping() { + return uniqueIdToDisplayIdMapping; + } + }); + } } } diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 558afd1da380..abbdeb9da364 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -33,13 +33,6 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPO import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; -import static com.android.server.display.DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED; -import static com.android.server.display.DisplayDeviceInfo.FLAG_DEVICE_DISPLAY_GROUP; -import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP; -import static com.android.server.display.DisplayDeviceInfo.FLAG_STEAL_TOP_FOCUS_DISABLED; -import static com.android.server.display.DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED; -import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED; - import android.annotation.Nullable; import android.content.Context; import android.graphics.Point; @@ -574,15 +567,13 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK; } else { mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; - - if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { - mInfo.flags |= FLAG_OWN_DISPLAY_GROUP; - } + } + if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { + mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP; } if ((mFlags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) { - mInfo.flags |= FLAG_DEVICE_DISPLAY_GROUP; + mInfo.flags |= DisplayDeviceInfo.FLAG_DEVICE_DISPLAY_GROUP; } - if ((mFlags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) { mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE; } @@ -611,41 +602,19 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mInfo.flags |= DisplayDeviceInfo.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { - mInfo.flags |= FLAG_TRUSTED; + mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED; } if ((mFlags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0) { - if ((mInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0 - || (mFlags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) { - mInfo.flags |= FLAG_ALWAYS_UNLOCKED; - } else { - Slog.w( - TAG, - "Ignoring VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED as it requires" - + " VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP or" - + " VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP."); - } + mInfo.flags |= DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED; } if ((mFlags & VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED) != 0) { - mInfo.flags |= FLAG_TOUCH_FEEDBACK_DISABLED; + mInfo.flags |= DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED; } if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_FOCUS) != 0) { - if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { - mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_FOCUS; - } else { - Slog.w(TAG, "Ignoring VIRTUAL_DISPLAY_FLAG_OWN_FOCUS as it requires " - + "VIRTUAL_DISPLAY_FLAG_TRUSTED."); - } + mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_FOCUS; } if ((mFlags & VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED) != 0) { - if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0 - && (mFlags & VIRTUAL_DISPLAY_FLAG_OWN_FOCUS) != 0) { - mInfo.flags |= FLAG_STEAL_TOP_FOCUS_DISABLED; - } else { - Slog.w(TAG, - "Ignoring VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED as it " - + "requires VIRTUAL_DISPLAY_FLAG_OWN_FOCUS which requires " - + "VIRTUAL_DISPLAY_FLAG_TRUSTED."); - } + mInfo.flags |= DisplayDeviceInfo.FLAG_STEAL_TOP_FOCUS_DISABLED; } mInfo.type = Display.TYPE_VIRTUAL; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java index 550f68fbc94c..733448aa0ffc 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java @@ -278,7 +278,8 @@ public class HdmiCecNetwork { } private void invokeDeviceEventListener(HdmiDeviceInfo info, int event) { - if (!hideDevicesBehindLegacySwitch(info)) { + if (event == HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE || + !hideDevicesBehindLegacySwitch(info)) { mHdmiControlService.invokeDeviceEventListeners(info, event); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index bd8b67b9d626..89f0d0edbf2b 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -710,7 +710,9 @@ public class HdmiControlService extends SystemService { // Register ContentObserver to monitor the settings change. registerContentObserver(); } - mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, ENABLED); + if (mMhlController != null) { + mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, ENABLED); + } } @VisibleForTesting @@ -1721,6 +1723,8 @@ public class HdmiControlService extends SystemService { if (result != SendMessageResult.SUCCESS) { localDevice.addAndStartAction(new ResendCecCommandAction(localDevice, command, callback)); + } else if (callback != null) { + callback.onSendCompleted(result); } } }); diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java index 1e54beeb2d64..b9352edf9230 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java @@ -372,25 +372,8 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub /* package */ void onEndpointSessionOpenRequest( int sessionId, HubEndpointInfo initiator, String serviceDescriptor) { - if (!hasEndpointPermissions(initiator)) { - halCloseEndpointSessionNoThrow(sessionId, Reason.PERMISSION_DENIED); - return; - } - - synchronized (mOpenSessionLock) { - if (hasSessionId(sessionId)) { - Log.e(TAG, "Existing session in onEndpointSessionOpenRequest: id=" + sessionId); - halCloseEndpointSessionNoThrow(sessionId, Reason.UNSPECIFIED); - return; - } - mSessionInfoMap.put(sessionId, new SessionInfo(initiator, true)); - } - boolean success = - invokeCallback( - (consumer) -> - consumer.onSessionOpenRequest( - sessionId, initiator, serviceDescriptor)); + onEndpointSessionOpenRequestInternal(sessionId, initiator, serviceDescriptor); if (!success) { cleanupSessionResources(sessionId); } @@ -439,6 +422,33 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } } + private boolean onEndpointSessionOpenRequestInternal( + int sessionId, HubEndpointInfo initiator, String serviceDescriptor) { + if (!hasEndpointPermissions(initiator)) { + Log.e( + TAG, + "onEndpointSessionOpenRequest: " + + initiator + + " doesn't have permission for " + + mEndpointInfo); + halCloseEndpointSessionNoThrow(sessionId, Reason.PERMISSION_DENIED); + return false; + } + + synchronized (mOpenSessionLock) { + if (hasSessionId(sessionId)) { + Log.e(TAG, "Existing session in onEndpointSessionOpenRequest: id=" + sessionId); + halCloseEndpointSessionNoThrow(sessionId, Reason.UNSPECIFIED); + return false; + } + mSessionInfoMap.put(sessionId, new SessionInfo(initiator, true)); + } + + return invokeCallback( + (consumer) -> + consumer.onSessionOpenRequest(sessionId, initiator, serviceDescriptor)); + } + private byte onMessageReceivedInternal(int sessionId, HubMessage message) { HubEndpointInfo remote; synchronized (mOpenSessionLock) { diff --git a/services/core/java/com/android/server/media/AudioManagerRouteController.java b/services/core/java/com/android/server/media/AudioManagerRouteController.java index 2686f2b30d27..14f870bd4e87 100644 --- a/services/core/java/com/android/server/media/AudioManagerRouteController.java +++ b/services/core/java/com/android/server/media/AudioManagerRouteController.java @@ -51,6 +51,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; /** * Maintains a list of all available routes and supports transfers to any of them. @@ -90,7 +91,11 @@ import java.util.Objects; @NonNull private final Context mContext; @NonNull private final AudioManager mAudioManager; @NonNull private final Handler mHandler; - @NonNull private final OnDeviceRouteChangedListener mOnDeviceRouteChangedListener; + + @NonNull + private final CopyOnWriteArrayList<OnDeviceRouteChangedListener> + mOnDeviceRouteChangedListeners = new CopyOnWriteArrayList<>(); + @NonNull private final BluetoothDeviceRoutesManager mBluetoothRouteController; @NonNull private final AudioProductStrategy mStrategyForMedia; @@ -112,6 +117,35 @@ import java.util.Objects; @NonNull private MediaRoute2Info mSelectedRoute; + // A singleton AudioManagerRouteController. + private static AudioManagerRouteController mInstance; + + // A flag indicating if the start function has been called. + private boolean mStarted = false; + + // Get the singleton AudioManagerRouteController. Create a new one if it's not available yet. + public static AudioManagerRouteController getInstance( + @NonNull Context context, + @NonNull AudioManager audioManager, + @NonNull Looper looper, + @NonNull AudioProductStrategy strategyForMedia, + @NonNull BluetoothAdapter btAdapter) { + if (!com.android.media.flags.Flags.enableUseOfSingletonAudioManagerRouteController()) { + return new AudioManagerRouteController( + context, audioManager, looper, strategyForMedia, btAdapter); + } + + synchronized (AudioManagerRouteController.class) { + if (mInstance == null) { + mInstance = + new AudioManagerRouteController( + context, audioManager, looper, strategyForMedia, btAdapter); + } + + return mInstance; + } + } + // TODO: b/305199571 - Support nullable btAdapter and strategyForMedia which, when null, means // no support for transferring to inactive bluetooth routes and transferring to any routes // respectively. @@ -125,13 +159,11 @@ import java.util.Objects; @NonNull AudioManager audioManager, @NonNull Looper looper, @NonNull AudioProductStrategy strategyForMedia, - @NonNull BluetoothAdapter btAdapter, - @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) { + @NonNull BluetoothAdapter btAdapter) { mContext = Objects.requireNonNull(context); mAudioManager = Objects.requireNonNull(audioManager); mHandler = new Handler(Objects.requireNonNull(looper)); mStrategyForMedia = Objects.requireNonNull(strategyForMedia); - mOnDeviceRouteChangedListener = Objects.requireNonNull(onDeviceRouteChangedListener); mBuiltInSpeakerSuitabilityStatus = DeviceRouteController.getBuiltInSpeakerSuitabilityStatus(mContext); @@ -144,6 +176,16 @@ import java.util.Objects; rebuildAvailableRoutes(); } + public void registerRouteChangeListener( + @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) { + mOnDeviceRouteChangedListeners.add(onDeviceRouteChangedListener); + } + + public void unregisterRouteChangeListener( + @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) { + mOnDeviceRouteChangedListeners.remove(onDeviceRouteChangedListener); + } + @RequiresPermission( anyOf = { Manifest.permission.MODIFY_AUDIO_ROUTING, @@ -151,7 +193,18 @@ import java.util.Objects; }) @Override public void start(UserHandle mUser) { - mBluetoothRouteController.start(mUser); + // When AudioManagerRouteController is singleton, only need to call this function once. + if (com.android.media.flags.Flags.enableUseOfSingletonAudioManagerRouteController()) { + if (mStarted) { + return; + } + mStarted = true; + } + + mBluetoothRouteController.start( + com.android.media.flags.Flags.enableUseOfSingletonAudioManagerRouteController() + ? UserHandle.SYSTEM + : mUser); mAudioManager.registerAudioDeviceCallback(mAudioDeviceCallback, mHandler); mAudioManager.addOnDevicesForAttributesChangedListener( AudioRoutingUtils.ATTRIBUTES_MEDIA, @@ -166,6 +219,11 @@ import java.util.Objects; }) @Override public void stop() { + // Singleton AudioManagerRouteController doesn't need to call stop function. + if (com.android.media.flags.Flags.enableUseOfSingletonAudioManagerRouteController()) { + return; + } + mAudioManager.removeOnDevicesForAttributesChangedListener( mOnDevicesForAttributesChangedListener); mAudioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback); @@ -281,7 +339,9 @@ import java.util.Objects; }) private void rebuildAvailableRoutesAndNotify() { rebuildAvailableRoutes(); - mOnDeviceRouteChangedListener.onDeviceRouteChanged(); + for (OnDeviceRouteChangedListener listener : mOnDeviceRouteChangedListeners) { + listener.onDeviceRouteChanged(); + } } @RequiresPermission( diff --git a/services/core/java/com/android/server/media/DeviceRouteController.java b/services/core/java/com/android/server/media/DeviceRouteController.java index dff0adfca370..0a4cbcd1ea31 100644 --- a/services/core/java/com/android/server/media/DeviceRouteController.java +++ b/services/core/java/com/android/server/media/DeviceRouteController.java @@ -65,13 +65,11 @@ import java.util.List; if (strategyForMedia != null && btAdapter != null && Flags.enableAudioPoliciesDeviceAndBluetoothController()) { - return new AudioManagerRouteController( - context, - audioManager, - looper, - strategyForMedia, - btAdapter, - onDeviceRouteChangedListener); + AudioManagerRouteController controller = + AudioManagerRouteController.getInstance( + context, audioManager, looper, strategyForMedia, btAdapter); + controller.registerRouteChangeListener(onDeviceRouteChangedListener); + return controller; } else { IAudioService audioService = IAudioService.Stub.asInterface( diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java index c428f39fd9d0..34a6cb951d46 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -58,6 +58,7 @@ import android.media.projection.IMediaProjection; import android.media.projection.IMediaProjectionCallback; import android.media.projection.IMediaProjectionManager; import android.media.projection.IMediaProjectionWatcherCallback; +import android.media.projection.MediaProjectionEvent; import android.media.projection.MediaProjectionInfo; import android.media.projection.MediaProjectionManager; import android.media.projection.ReviewGrantedConsentResult; @@ -80,6 +81,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; +import com.android.media.projection.flags.Flags; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.Watchdog; @@ -177,9 +179,31 @@ public final class MediaProjectionManagerService extends SystemService private void maybeStopMediaProjection(int reason) { synchronized (mLock) { - if (!mMediaProjectionStopController.isExemptFromStopping(mProjectionGrant, reason)) { - Slog.d(TAG, "Content Recording: Stopping MediaProjection due to " - + MediaProjectionStopController.stopReasonToString(reason)); + if (mMediaProjectionStopController.isExemptFromStopping(mProjectionGrant, reason)) { + return; + } + + if (Flags.showStopDialogPostCallEnd() + && mMediaProjectionStopController.isStopReasonCallEnd(reason)) { + MediaProjectionEvent event = + new MediaProjectionEvent( + MediaProjectionEvent + .PROJECTION_STARTED_DURING_CALL_AND_ACTIVE_POST_CALL, + System.currentTimeMillis()); + Slog.d( + TAG, + "Scheduling event: " + + event.getEventType() + + " for reason: " + + MediaProjectionStopController.stopReasonToString(reason)); + + // Post the PROJECTION_STARTED_DURING_CALL_AND_ACTIVE_POST_CALL event with a delay. + mHandler.postDelayed(() -> dispatchEvent(event), 500); + } else { + Slog.d( + TAG, + "Stopping MediaProjection due to reason: " + + MediaProjectionStopController.stopReasonToString(reason)); mProjectionGrant.stop(StopReason.STOP_DEVICE_LOCKED); } } @@ -388,6 +412,24 @@ public final class MediaProjectionManagerService extends SystemService mCallbackDelegate.dispatchSession(projectionInfo, session); } + private void dispatchEvent(@NonNull MediaProjectionEvent event) { + if (!Flags.showStopDialogPostCallEnd()) { + Slog.d( + TAG, + "Event dispatch skipped. Reason: Flag showStopDialogPostCallEnd " + + "is disabled. Event details: " + + event); + return; + } + MediaProjectionInfo projectionInfo; + ContentRecordingSession session; + synchronized (mLock) { + projectionInfo = mProjectionGrant != null ? mProjectionGrant.getProjectionInfo() : null; + session = mProjectionGrant != null ? mProjectionGrant.mSession : null; + } + mCallbackDelegate.dispatchEvent(event, projectionInfo, session); + } + /** * Returns {@code true} when updating the current mirroring session on WM succeeded, and * {@code false} otherwise. @@ -1467,6 +1509,25 @@ public final class MediaProjectionManagerService extends SystemService } } + private void dispatchEvent( + @NonNull MediaProjectionEvent event, + @Nullable MediaProjectionInfo info, + @Nullable ContentRecordingSession session) { + if (!Flags.showStopDialogPostCallEnd()) { + Slog.d( + TAG, + "Event dispatch skipped. Reason: Flag showStopDialogPostCallEnd " + + "is disabled. Event details: " + + event); + return; + } + synchronized (mLock) { + for (IMediaProjectionWatcherCallback callback : mWatcherCallbacks.values()) { + mHandler.post(new WatcherEventCallback(callback, event, info, session)); + } + } + } + public void dispatchSession( @NonNull MediaProjectionInfo projectionInfo, @Nullable ContentRecordingSession session) { @@ -1593,6 +1654,41 @@ public final class MediaProjectionManagerService extends SystemService } } + private static final class WatcherEventCallback implements Runnable { + private final IMediaProjectionWatcherCallback mCallback; + private final MediaProjectionEvent mEvent; + private final MediaProjectionInfo mProjectionInfo; + private final ContentRecordingSession mSession; + + WatcherEventCallback( + @NonNull IMediaProjectionWatcherCallback callback, + @NonNull MediaProjectionEvent event, + @Nullable MediaProjectionInfo projectionInfo, + @Nullable ContentRecordingSession session) { + mCallback = callback; + mEvent = event; + mProjectionInfo = projectionInfo; + mSession = session; + } + + @Override + public void run() { + if (!Flags.showStopDialogPostCallEnd()) { + Slog.d( + TAG, + "Not running WatcherEventCallback. Reason: Flag " + + "showStopDialogPostCallEnd is disabled. " + ); + return; + } + try { + mCallback.onMediaProjectionEvent(mEvent, mProjectionInfo, mSession); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to notify MediaProjectionEvent change", e); + } + } + } + private static final class WatcherSessionCallback implements Runnable { private final IMediaProjectionWatcherCallback mCallback; private final MediaProjectionInfo mProjectionInfo; diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java b/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java index c018e6bc1dc7..2e0bb4f88485 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java @@ -95,6 +95,11 @@ public class MediaProjectionStopController { } } + /** Checks if the given stop reason corresponds to a call ending. */ + public boolean isStopReasonCallEnd(int stopReason) { + return stopReason == STOP_REASON_CALL_END; + } + /** * Checks whether the given projection grant is exempt from stopping restrictions. */ diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java index 6ad7ea7b768f..2a5b779546d5 100644 --- a/services/core/java/com/android/server/media/quality/MediaQualityService.java +++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java @@ -72,6 +72,8 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.File; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -1067,35 +1069,37 @@ public class MediaQualityService extends SystemService { } } - enum Mode { - ADD, - UPDATE, - REMOVE, - ERROR + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + private @interface ProfileModes { + int ADD = 1; + int UPDATE = 2; + int REMOVE = 3; + int ERROR = 4; } private void notifyOnPictureProfileAdded(String profileId, PictureProfile profile, int uid, int pid) { - notifyPictureProfileHelper(Mode.ADD, profileId, profile, null, uid, pid); + notifyPictureProfileHelper(ProfileModes.ADD, profileId, profile, null, uid, pid); } private void notifyOnPictureProfileUpdated(String profileId, PictureProfile profile, int uid, int pid) { - notifyPictureProfileHelper(Mode.UPDATE, profileId, profile, null, uid, pid); + notifyPictureProfileHelper(ProfileModes.UPDATE, profileId, profile, null, uid, pid); } private void notifyOnPictureProfileRemoved(String profileId, PictureProfile profile, int uid, int pid) { - notifyPictureProfileHelper(Mode.REMOVE, profileId, profile, null, uid, pid); + notifyPictureProfileHelper(ProfileModes.REMOVE, profileId, profile, null, uid, pid); } private void notifyOnPictureProfileError(String profileId, int errorCode, int uid, int pid) { - notifyPictureProfileHelper(Mode.ERROR, profileId, null, errorCode, uid, pid); + notifyPictureProfileHelper(ProfileModes.ERROR, profileId, null, errorCode, uid, pid); } - private void notifyPictureProfileHelper(Mode mode, String profileId, PictureProfile profile, - Integer errorCode, int uid, int pid) { + private void notifyPictureProfileHelper(int mode, String profileId, + PictureProfile profile, Integer errorCode, int uid, int pid) { UserState userState = getOrCreateUserStateLocked(UserHandle.USER_SYSTEM); int n = userState.mPictureProfileCallbacks.beginBroadcast(); @@ -1107,28 +1111,28 @@ public class MediaQualityService extends SystemService { .get(callback); if (pidUid.first == pid && pidUid.second == uid) { - if (mode == Mode.ADD) { + if (mode == ProfileModes.ADD) { userState.mPictureProfileCallbacks.getBroadcastItem(i) .onPictureProfileAdded(profileId, profile); - } else if (mode == Mode.UPDATE) { + } else if (mode == ProfileModes.UPDATE) { userState.mPictureProfileCallbacks.getBroadcastItem(i) .onPictureProfileUpdated(profileId, profile); - } else if (mode == Mode.REMOVE) { + } else if (mode == ProfileModes.REMOVE) { userState.mPictureProfileCallbacks.getBroadcastItem(i) .onPictureProfileRemoved(profileId, profile); - } else if (mode == Mode.ERROR) { + } else if (mode == ProfileModes.ERROR) { userState.mPictureProfileCallbacks.getBroadcastItem(i) .onError(profileId, errorCode); } } } catch (RemoteException e) { - if (mode == Mode.ADD) { + if (mode == ProfileModes.ADD) { Slog.e(TAG, "Failed to report added picture profile to callback", e); - } else if (mode == Mode.UPDATE) { + } else if (mode == ProfileModes.UPDATE) { Slog.e(TAG, "Failed to report updated picture profile to callback", e); - } else if (mode == Mode.REMOVE) { + } else if (mode == ProfileModes.REMOVE) { Slog.e(TAG, "Failed to report removed picture profile to callback", e); - } else if (mode == Mode.ERROR) { + } else if (mode == ProfileModes.ERROR) { Slog.e(TAG, "Failed to report picture profile error to callback", e); } } @@ -1138,25 +1142,25 @@ public class MediaQualityService extends SystemService { private void notifyOnSoundProfileAdded(String profileId, SoundProfile profile, int uid, int pid) { - notifySoundProfileHelper(Mode.ADD, profileId, profile, null, uid, pid); + notifySoundProfileHelper(ProfileModes.ADD, profileId, profile, null, uid, pid); } private void notifyOnSoundProfileUpdated(String profileId, SoundProfile profile, int uid, int pid) { - notifySoundProfileHelper(Mode.UPDATE, profileId, profile, null, uid, pid); + notifySoundProfileHelper(ProfileModes.UPDATE, profileId, profile, null, uid, pid); } private void notifyOnSoundProfileRemoved(String profileId, SoundProfile profile, int uid, int pid) { - notifySoundProfileHelper(Mode.REMOVE, profileId, profile, null, uid, pid); + notifySoundProfileHelper(ProfileModes.REMOVE, profileId, profile, null, uid, pid); } private void notifyOnSoundProfileError(String profileId, int errorCode, int uid, int pid) { - notifySoundProfileHelper(Mode.ERROR, profileId, null, errorCode, uid, pid); + notifySoundProfileHelper(ProfileModes.ERROR, profileId, null, errorCode, uid, pid); } - private void notifySoundProfileHelper(Mode mode, String profileId, SoundProfile profile, - Integer errorCode, int uid, int pid) { + private void notifySoundProfileHelper(int mode, String profileId, + SoundProfile profile, Integer errorCode, int uid, int pid) { UserState userState = getOrCreateUserStateLocked(UserHandle.USER_SYSTEM); int n = userState.mSoundProfileCallbacks.beginBroadcast(); @@ -1168,28 +1172,28 @@ public class MediaQualityService extends SystemService { .get(callback); if (pidUid.first == pid && pidUid.second == uid) { - if (mode == Mode.ADD) { + if (mode == ProfileModes.ADD) { userState.mSoundProfileCallbacks.getBroadcastItem(i) .onSoundProfileAdded(profileId, profile); - } else if (mode == Mode.UPDATE) { + } else if (mode == ProfileModes.UPDATE) { userState.mSoundProfileCallbacks.getBroadcastItem(i) .onSoundProfileUpdated(profileId, profile); - } else if (mode == Mode.REMOVE) { + } else if (mode == ProfileModes.REMOVE) { userState.mSoundProfileCallbacks.getBroadcastItem(i) .onSoundProfileRemoved(profileId, profile); - } else if (mode == Mode.ERROR) { + } else if (mode == ProfileModes.ERROR) { userState.mSoundProfileCallbacks.getBroadcastItem(i) .onError(profileId, errorCode); } } } catch (RemoteException e) { - if (mode == Mode.ADD) { + if (mode == ProfileModes.ADD) { Slog.e(TAG, "Failed to report added sound profile to callback", e); - } else if (mode == Mode.UPDATE) { + } else if (mode == ProfileModes.UPDATE) { Slog.e(TAG, "Failed to report updated sound profile to callback", e); - } else if (mode == Mode.REMOVE) { + } else if (mode == ProfileModes.REMOVE) { Slog.e(TAG, "Failed to report removed sound profile to callback", e); - } else if (mode == Mode.ERROR) { + } else if (mode == ProfileModes.ERROR) { Slog.e(TAG, "Failed to report sound profile error to callback", e); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 588e87924b7d..daa1042bb255 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -258,7 +258,6 @@ import android.metrics.LogMaker; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkRequest; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -2834,33 +2833,25 @@ public class NotificationManagerService extends SystemService { } private void registerNetworkCallback() { - NetworkRequest request = new NetworkRequest.Builder().addTransportType( - NetworkCapabilities.TRANSPORT_WIFI).build(); - mConnectivityManager.registerNetworkCallback(request, + mConnectivityManager.registerDefaultNetworkCallback( new ConnectivityManager.NetworkCallback() { - // Need to post to another thread, as we can't call synchronous ConnectivityManager - // methods from the callback itself, due to potential race conditions. - @Override - public void onAvailable(@NonNull Network network) { - mHandler.post(() -> updateWifiConnectionState()); - } - @Override - public void onLost(@NonNull Network network) { - mHandler.post(() -> updateWifiConnectionState()); - } - }); - updateWifiConnectionState(); + @Override + public void onCapabilitiesChanged(@NonNull Network network, + @NonNull NetworkCapabilities capabilities) { + updateWifiConnectionState(capabilities); + } + @Override + public void onLost(@NonNull Network network) { + mConnectedToWifi = false; + } + }, mHandler); } @VisibleForTesting() - void updateWifiConnectionState() { - Network current = mConnectivityManager.getActiveNetwork(); - NetworkCapabilities capabilities = mConnectivityManager.getNetworkCapabilities(current); - if (current == null || capabilities == null) { - mConnectedToWifi = false; - return; - } - mConnectedToWifi = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI); + void updateWifiConnectionState(NetworkCapabilities capabilities) { + mConnectedToWifi = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) + && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED); } /** diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 6303ecd53dbb..8710438d76b3 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -1064,10 +1064,12 @@ public final class OverlayManagerService extends SystemService { return; } try { - dumpState.setUserId(Integer.parseInt(args[opti])); + final int userId = UserHandle.parseUserArg(args[opti]); + final int realUserId = handleIncomingUser(userId, "dump"); + dumpState.setUserId(realUserId); opti++; - } catch (NumberFormatException e) { - pw.println("Error: user argument is not a number: " + args[opti]); + } catch (Exception e) { + pw.println("Error: " + e.getMessage()); return; } } else if ("--verbose".equals(opt)) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index b85e6894b910..a2c53e56b9c9 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -57,6 +57,10 @@ import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SpecialUsers.CanBeALL; +import android.annotation.SpecialUsers.CanBeCURRENT; +import android.annotation.SpecialUsers.CanBeNULL; +import android.annotation.SpecialUsers.CannotBeSpecialUser; import android.annotation.StringRes; import android.annotation.UserIdInt; import android.app.ActivityManager; @@ -952,7 +956,7 @@ public class UserManagerService extends IUserManager.Stub { private final UserVisibilityMediator mUserVisibilityMediator; @GuardedBy("mUsersLock") - private @UserIdInt int mBootUser = UserHandle.USER_NULL; + private @CanBeNULL @UserIdInt int mBootUser = UserHandle.USER_NULL; private static UserManagerService sInstance; @@ -1333,12 +1337,12 @@ public class UserManagerService extends IUserManager.Stub { } @Override - public @UserIdInt int getMainUserId() { + public @CanBeNULL @UserIdInt int getMainUserId() { checkQueryOrCreateUsersPermission("get main user id"); return getMainUserIdUnchecked(); } - private @UserIdInt int getMainUserIdUnchecked() { + private @CanBeNULL @UserIdInt int getMainUserIdUnchecked() { synchronized (mUsersLock) { final int userSize = mUsers.size(); for (int i = 0; i < userSize; i++) { @@ -1351,7 +1355,7 @@ public class UserManagerService extends IUserManager.Stub { return UserHandle.USER_NULL; } - private @UserIdInt int getPrivateProfileUserId() { + private @CanBeNULL @UserIdInt int getPrivateProfileUserId() { synchronized (mUsersLock) { for (int userId : getUserIds()) { UserInfo userInfo = getUserInfoLU(userId); @@ -1455,7 +1459,7 @@ public class UserManagerService extends IUserManager.Stub { "No switchable users found", USER_OPERATION_ERROR_UNKNOWN); } - private @UserIdInt int getFirstSwitchableUser(boolean fullUserOnly) { + private @CanBeNULL @UserIdInt int getFirstSwitchableUser(boolean fullUserOnly) { synchronized (mUsersLock) { final int userSize = mUsers.size(); for (int i = 0; i < userSize; i++) { @@ -1472,7 +1476,7 @@ public class UserManagerService extends IUserManager.Stub { @Override - public int getPreviousFullUserToEnterForeground() { + public @CanBeNULL @UserIdInt int getPreviousFullUserToEnterForeground() { checkQueryOrCreateUsersPermission("get previous user"); int previousUser = UserHandle.USER_NULL; long latestEnteredTime = 0; @@ -1496,13 +1500,13 @@ public class UserManagerService extends IUserManager.Stub { } @Override - public @UserIdInt int getCommunalProfileId() { + public @CanBeNULL @UserIdInt int getCommunalProfileId() { checkQueryOrCreateUsersPermission("get communal profile user id"); return getCommunalProfileIdUnchecked(); } /** Returns the currently-designated communal profile, or USER_NULL if not present. */ - private @UserIdInt int getCommunalProfileIdUnchecked() { + private @CanBeNULL @UserIdInt int getCommunalProfileIdUnchecked() { synchronized (mUsersLock) { final int userSize = mUsers.size(); for (int i = 0; i < userSize; i++) { @@ -2675,7 +2679,7 @@ public class UserManagerService extends IUserManager.Stub { * {@link ActivityManagerInternal} is not available yet. */ @VisibleForTesting - int getCurrentUserId() { + @CanBeNULL @UserIdInt int getCurrentUserId() { ActivityManagerInternal activityManagerInternal = getActivityManagerInternal(); if (activityManagerInternal == null) { Slog.w(LOG_TAG, "getCurrentUserId() called too early, ActivityManagerInternal" @@ -2918,7 +2922,16 @@ public class UserManagerService extends IUserManager.Stub { * switchable. */ public @UserManager.UserSwitchabilityResult int getUserSwitchability(int userId) { - checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "getUserSwitchability"); + if (Flags.getUserSwitchabilityPermission()) { + if (!hasManageUsersOrPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)) { + throw new SecurityException( + "You need MANAGE_USERS or INTERACT_ACROSS_USERS permission to " + + "getUserSwitchability"); + } + } else { + checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, + "getUserSwitchability"); + } final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); t.traceBegin("getUserSwitchability-" + userId); @@ -2974,27 +2987,27 @@ public class UserManagerService extends IUserManager.Stub { } @VisibleForTesting - boolean isUserSwitcherEnabled(@UserIdInt int mUserId) { + boolean isUserSwitcherEnabled(@UserIdInt int userId) { boolean multiUserSettingOn = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.USER_SWITCHER_ENABLED, Resources.getSystem().getBoolean(com.android.internal .R.bool.config_showUserSwitcherByDefault) ? 1 : 0) != 0; return UserManager.supportsMultipleUsers() - && !hasUserRestriction(DISALLOW_USER_SWITCH, mUserId) + && !hasUserRestriction(DISALLOW_USER_SWITCH, userId) && !UserManager.isDeviceInDemoMode(mContext) && multiUserSettingOn; } @Override public boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable, - @UserIdInt int mUserId) { - if (!isUserSwitcherEnabled(mUserId)) { + @UserIdInt int userId) { + if (!isUserSwitcherEnabled(userId)) { return false; } // The feature is enabled. But is it worth showing? return showEvenIfNotActionable - || !hasUserRestriction(UserManager.DISALLOW_ADD_USER, mUserId) // Can add new user + || !hasUserRestriction(UserManager.DISALLOW_ADD_USER, userId) // Can add new user || areThereMultipleSwitchableUsers(); // There are switchable users } @@ -3427,7 +3440,8 @@ public class UserManagerService extends IUserManager.Stub { } @VisibleForTesting - void setUserRestrictionInner(int userId, @NonNull String key, boolean value) { + void setUserRestrictionInner( + @CanBeALL @UserIdInt int userId, @NonNull String key, boolean value) { if (!UserRestrictionsUtils.isValidRestriction(key)) { Slog.e(LOG_TAG, "Setting invalid restriction " + key); return; @@ -3520,10 +3534,11 @@ public class UserManagerService extends IUserManager.Stub { /** @return a specific user restriction that's in effect currently. */ @Override public boolean hasUserRestriction(String restrictionKey, @UserIdInt int userId) { + checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "hasUserRestriction"); + // TODO(b/390455855): Should this be (!userExists(userId) && userId != UserHandle.USER_ALL)? if (!userExists(userId)) { return false; } - checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "hasUserRestriction"); return mLocalService.hasUserRestriction(restrictionKey, userId); } @@ -5610,7 +5625,7 @@ public class UserManagerService extends IUserManager.Stub { private @NonNull UserInfo createUserInternal( @Nullable String name, @NonNull String userType, - @UserInfoFlag int flags, @UserIdInt int parentId, + @UserInfoFlag int flags, @CanBeNULL @UserIdInt int parentId, @Nullable String[] disallowedPackages) throws UserManager.CheckedUserOperationException { @@ -5643,8 +5658,8 @@ public class UserManagerService extends IUserManager.Stub { private @NonNull UserInfo createUserInternalUnchecked( @Nullable String name, @NonNull String userType, @UserInfoFlag int flags, - @UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages, - @Nullable Object token) + @CanBeNULL @UserIdInt int parentId, boolean preCreate, + @Nullable String[] disallowedPackages, @Nullable Object token) throws UserManager.CheckedUserOperationException { final int noneUserId = -1; @@ -6227,9 +6242,11 @@ public class UserManagerService extends IUserManager.Stub { if (UserManager.getMaxSupportedUsers() > 1) { data.add(FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.MULTI_USER_INFO, UserManager.getMaxSupportedUsers(), + // TODO(b/390455855): is USER_ALL really allowed here? isUserSwitcherEnabled(UserHandle.USER_ALL), UserManager.supportsMultipleUsers() && !hasUserRestriction(UserManager.DISALLOW_ADD_USER, + // TODO(b/390455855): is USER_ALL really allowed here? UserHandle.USER_ALL))); } } else { @@ -7580,8 +7597,8 @@ public class UserManagerService extends IUserManager.Stub { } } - private void dumpUser(PrintWriter pw, @UserIdInt int userId, StringBuilder sb, long now, - long nowRealtime) { + private void dumpUser(PrintWriter pw, @CanBeCURRENT @UserIdInt int userId, StringBuilder sb, + long now, long nowRealtime) { if (userId == UserHandle.USER_CURRENT) { final int currentUserId = getCurrentUserId(); pw.print("Current user: "); @@ -7755,7 +7772,7 @@ public class UserManagerService extends IUserManager.Stub { } @Override - public void setUserRestriction(int userId, @NonNull String key, boolean value) { + public void setUserRestriction(@UserIdInt int userId, @NonNull String key, boolean value) { UserManagerService.this.setUserRestrictionInner(userId, key, value); } diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java index 441d3eaf2348..142d919da455 100644 --- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java +++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java @@ -24,6 +24,8 @@ import android.util.Log; import android.view.KeyEvent; import android.view.ViewConfiguration; +import com.android.hardware.input.Flags; + import java.io.PrintWriter; import java.util.ArrayList; @@ -355,6 +357,19 @@ public final class SingleKeyGestureDetector { } if (event.getKeyCode() == mActiveRule.mKeyCode) { + if (Flags.abortSlowMultiPress() + && (event.getEventTime() - mLastDownTime + >= mActiveRule.getLongPressTimeoutMs())) { + // In this case, we are either on a first long press (but long press behavior is not + // supported for this rule), or, on a non-first press that is at least as long as + // the long-press duration. Thus, we will cancel the multipress gesture. + if (DEBUG) { + Log.d(TAG, "The duration of the press is too slow. Resetting."); + } + reset(); + return false; + } + // key-up action should always be triggered if not processed by long press. MessageObject object = new MessageObject(mActiveRule, mActiveRule.mKeyCode, mKeyPressCounter, event); diff --git a/services/core/java/com/android/server/security/FileIntegrityService.java b/services/core/java/com/android/server/security/FileIntegrityService.java index 587be0746149..bfd86d724583 100644 --- a/services/core/java/com/android/server/security/FileIntegrityService.java +++ b/services/core/java/com/android/server/security/FileIntegrityService.java @@ -17,47 +17,24 @@ package com.android.server.security; import android.annotation.EnforcePermission; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.os.Binder; -import android.os.Build; -import android.os.Environment; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.PermissionEnforcer; import android.os.RemoteException; -import android.os.ResultReceiver; -import android.os.ShellCallback; -import android.os.ShellCommand; import android.os.UserHandle; import android.os.storage.StorageManagerInternal; import android.security.IFileIntegrityService; -import android.util.Slog; -import com.android.internal.annotations.GuardedBy; import com.android.internal.security.VerityUtils; import com.android.server.LocalServices; import com.android.server.SystemService; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileDescriptor; import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.ArrayList; import java.util.Objects; /** @@ -67,15 +44,6 @@ import java.util.Objects; public class FileIntegrityService extends SystemService { private static final String TAG = "FileIntegrityService"; - /** The maximum size of signature file. This is just to avoid potential abuse. */ - private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192; - - private static CertificateFactory sCertFactory; - - @GuardedBy("mTrustedCertificates") - private final ArrayList<X509Certificate> mTrustedCertificates = - new ArrayList<X509Certificate>(); - /** Gets the instance of the service */ public static FileIntegrityService getService() { return LocalServices.getService(FileIntegrityService.class); @@ -91,43 +59,6 @@ public class FileIntegrityService extends SystemService { return VerityUtils.isFsVeritySupported(); } - @Override - public boolean isAppSourceCertificateTrusted(@Nullable byte[] certificateBytes, - @NonNull String packageName) { - checkCallerPermission(packageName); - - if (android.security.Flags.deprecateFsvSig()) { - // When deprecated, stop telling the caller that any app source certificate is - // trusted on the current device. This behavior is also consistent with devices - // without this feature support. - return false; - } - - try { - if (!VerityUtils.isFsVeritySupported()) { - return false; - } - if (certificateBytes == null) { - Slog.w(TAG, "Received a null certificate"); - return false; - } - synchronized (mTrustedCertificates) { - return mTrustedCertificates.contains(toCertificate(certificateBytes)); - } - } catch (CertificateException e) { - Slog.e(TAG, "Failed to convert the certificate: " + e); - return false; - } - } - - @Override - public void onShellCommand(FileDescriptor in, FileDescriptor out, - FileDescriptor err, String[] args, ShellCallback callback, - ResultReceiver resultReceiver) { - new FileIntegrityServiceShellCommand() - .exec(this, in, out, err, args, callback, resultReceiver); - } - private void checkCallerPackageName(String packageName) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); @@ -195,12 +126,6 @@ public class FileIntegrityService extends SystemService { public FileIntegrityService(final Context context) { super(context); mService = new BinderService(context); - try { - sCertFactory = CertificateFactory.getInstance("X.509"); - } catch (CertificateException e) { - Slog.wtf(TAG, "Cannot get an instance of X.509 certificate factory"); - } - LocalServices.addService(FileIntegrityService.class, this); } @@ -215,155 +140,6 @@ public class FileIntegrityService extends SystemService { @Override public void onStart() { - loadAllCertificates(); publishBinderService(Context.FILE_INTEGRITY_SERVICE, mService); } - - /** - * Returns whether the signature over the file's fs-verity digest can be verified by one of the - * known certiticates. - */ - public boolean verifyPkcs7DetachedSignature(String signaturePath, String filePath) - throws IOException { - if (Files.size(Paths.get(signaturePath)) > MAX_SIGNATURE_FILE_SIZE_BYTES) { - throw new SecurityException("Signature file is unexpectedly large: " - + signaturePath); - } - byte[] signatureBytes = Files.readAllBytes(Paths.get(signaturePath)); - byte[] digest = VerityUtils.getFsverityDigest(filePath); - synchronized (mTrustedCertificates) { - for (var cert : mTrustedCertificates) { - try { - byte[] derEncoded = cert.getEncoded(); - if (VerityUtils.verifyPkcs7DetachedSignature(signatureBytes, digest, - new ByteArrayInputStream(derEncoded))) { - return true; - } - } catch (CertificateEncodingException e) { - Slog.w(TAG, "Ignoring ill-formed certificate: " + e); - } - } - } - return false; - } - - private void loadAllCertificates() { - // Load certificates trusted by the device manufacturer. - final String relativeDir = "etc/security/fsverity"; - loadCertificatesFromDirectory(Environment.getRootDirectory().toPath() - .resolve(relativeDir)); - loadCertificatesFromDirectory(Environment.getProductDirectory().toPath() - .resolve(relativeDir)); - } - - private void loadCertificatesFromDirectory(Path path) { - try { - File[] files = path.toFile().listFiles(); - if (files == null) { - return; - } - - for (File cert : files) { - byte[] certificateBytes = Files.readAllBytes(cert.toPath()); - collectCertificate(certificateBytes); - } - } catch (IOException e) { - Slog.wtf(TAG, "Failed to load fs-verity certificate from " + path, e); - } - } - - /** - * Tries to convert {@code bytes} into an X.509 certificate and store in memory. - * Errors need to be surpressed in order fo the next certificates to still be collected. - */ - private void collectCertificate(@NonNull byte[] bytes) { - try { - synchronized (mTrustedCertificates) { - mTrustedCertificates.add(toCertificate(bytes)); - } - } catch (CertificateException e) { - Slog.e(TAG, "Invalid certificate, ignored: " + e); - } - } - - /** - * Converts byte array into one X.509 certificate. If multiple certificate is defined, ignore - * the rest. The rational is to make it harder to smuggle. - */ - @NonNull - private static X509Certificate toCertificate(@NonNull byte[] bytes) - throws CertificateException { - Certificate certificate = sCertFactory.generateCertificate(new ByteArrayInputStream(bytes)); - if (!(certificate instanceof X509Certificate)) { - throw new CertificateException("Expected to contain an X.509 certificate"); - } - return (X509Certificate) certificate; - } - - - private class FileIntegrityServiceShellCommand extends ShellCommand { - @Override - public int onCommand(String cmd) { - if (!Build.IS_DEBUGGABLE) { - return -1; - } - if (cmd == null) { - return handleDefaultCommands(cmd); - } - final PrintWriter pw = getOutPrintWriter(); - switch (cmd) { - case "append-cert": - String nextArg = getNextArg(); - if (nextArg == null) { - pw.println("Invalid argument"); - pw.println(""); - onHelp(); - return -1; - } - ParcelFileDescriptor pfd = openFileForSystem(nextArg, "r"); - if (pfd == null) { - pw.println("Cannot open the file"); - return -1; - } - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd); - try { - collectCertificate(is.readAllBytes()); - } catch (IOException e) { - pw.println("Failed to add certificate: " + e); - return -1; - } - pw.println("Certificate is added successfully"); - return 0; - - case "remove-last-cert": - synchronized (mTrustedCertificates) { - if (mTrustedCertificates.size() == 0) { - pw.println("Certificate list is already empty"); - return -1; - } - mTrustedCertificates.remove(mTrustedCertificates.size() - 1); - } - pw.println("Certificate is removed successfully"); - return 0; - default: - pw.println("Unknown action"); - pw.println(""); - onHelp(); - } - return -1; - } - - @Override - public void onHelp() { - final PrintWriter pw = getOutPrintWriter(); - pw.println("File integrity service commands:"); - pw.println(" help"); - pw.println(" Print this help text."); - pw.println(" append-cert path/to/cert.der"); - pw.println(" Add the DER-encoded certificate (only in debug builds)"); - pw.println(" remove-last-cert"); - pw.println(" Remove the last certificate in the key list (only in debug builds)"); - pw.println(""); - } - } } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index b7ce050aaadd..4827c9f414ad 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -177,6 +177,13 @@ public interface StatusBarManagerInternal { */ void onDisplayReady(int displayId); + /** + * Notifies System UI that the system decorations should be removed from the display. + * + * @param displayId display ID + */ + void onDisplayRemoveSystemDecorations(int displayId); + /** @see com.android.internal.statusbar.IStatusBar#onSystemBarAttributesChanged */ void onSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, @@ -275,7 +282,13 @@ public interface StatusBarManagerInternal { */ void moveFocusedTaskToDesktop(int displayId); - /** Passes through the given shell commands to SystemUI */ void passThroughShellCommand(String[] args, FileDescriptor fd); + + /** + * Set whether the display should have a navigation bar. + * + * TODO(b/390591772): Refactor this method + */ + void setHasNavigationBar(int displayId, boolean hasNavigationBar); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 4ece470d9b8d..37056a4af250 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -793,6 +793,26 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override + public void onDisplayRemoveSystemDecorations(int displayId) { + if (isVisibleBackgroundUserOnDisplay(displayId)) { + if (SPEW) { + Slog.d(TAG, + "Skipping onDisplayRemoveSystemDecorations for visible background " + + "user " + + mUserManagerInternal.getUserAssignedToDisplay(displayId)); + } + return; + } + + IStatusBar bar = mBar; + if (bar != null) { + try { + bar.onDisplayRemoveSystemDecorations(displayId); + } catch (RemoteException ex) {} + } + } + + @Override public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, @Behavior int behavior, @InsetsType int requestedVisibleTypes, @@ -996,6 +1016,23 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D public void passThroughShellCommand(String[] args, FileDescriptor fd) { StatusBarManagerService.this.passThroughShellCommand(args, fd); } + + @Override + public void setHasNavigationBar(int displayId, boolean hasNavigationBar) { + if (isVisibleBackgroundUserOnDisplay(displayId)) { + if (SPEW) { + Slog.d(TAG, "Skipping setHasNavigationBar for visible background user " + + mUserManagerInternal.getUserAssignedToDisplay(displayId)); + } + return; + } + IStatusBar bar = mBar; + if (bar != null) { + try { + bar.setHasNavigationBar(displayId, hasNavigationBar); + } catch (RemoteException ex) {} + } + } }; private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() { @@ -1542,10 +1579,13 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D getUiState(displayId).setImeWindowState(vis, backDisposition, showImeSwitcher); mHandler.post(() -> { - if (mBar == null) return; - try { - mBar.setImeWindowStatus(displayId, vis, backDisposition, showImeSwitcher); - } catch (RemoteException ex) { } + IStatusBar bar = mBar; + if (bar != null) { + try { + bar.setImeWindowStatus(displayId, vis, backDisposition, showImeSwitcher); + } catch (RemoteException ex) { + } + } }); } } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 415896b6230f..a8deeeac311d 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE; import static android.Manifest.permission.READ_WALLPAPER_INTERNAL; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; +import static android.app.Flags.enableConnectedDisplaysWallpaper; import static android.app.Flags.fixWallpaperChanged; import static android.app.Flags.liveWallpaperContentHandling; import static android.app.Flags.removeNextWallpaperComponent; @@ -89,6 +90,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; import android.multiuser.Flags; import android.os.Binder; import android.os.Bundle; @@ -655,8 +657,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub private final MyPackageMonitor mMonitor; private final AppOpsManager mAppOpsManager; - private final DisplayManager.DisplayListener mDisplayListener = - new DisplayManager.DisplayListener() { + private final DisplayListener mDisplayListener = new DisplayListener() { @Override public void onDisplayAdded(int displayId) { @@ -665,24 +666,64 @@ public class WallpaperManagerService extends IWallpaperManager.Stub @Override public void onDisplayRemoved(int displayId) { synchronized (mLock) { - if (mLastWallpaper != null) { - WallpaperData targetWallpaper = null; - if (mLastWallpaper.connection != null && - mLastWallpaper.connection.containsDisplay(displayId)) { - targetWallpaper = mLastWallpaper; - } else if (mFallbackWallpaper != null && - mFallbackWallpaper.connection != null && - mFallbackWallpaper.connection.containsDisplay(displayId)) { - targetWallpaper = mFallbackWallpaper; + if (enableConnectedDisplaysWallpaper()) { + // There could be at most 2 wallpaper connections per display: + // 1. system & lock are the same: mLastWallpaper + // 2. system, lock are different: mLastWallpaper, mLastLockWallpaper + // 3. fallback used as both system & lock wallpaper: mFallbackWallpaper + // 4. fallback used as lock only wallpaper: mFallbackWallpaper, + // mLastWallpaper + // 5. fallback used as system only wallpaper: mFallbackWallpaper, + // mLastLockWallpaper + List<WallpaperData> pendingDisconnectWallpapers = new ArrayList<>(); + if (mLastWallpaper != null && mLastWallpaper.connection != null + && mLastWallpaper.connection.containsDisplay(displayId)) { + pendingDisconnectWallpapers.add(mLastWallpaper); + } + if (mLastLockWallpaper != null && mLastLockWallpaper.connection != null + && mLastLockWallpaper.connection.containsDisplay(displayId)) { + pendingDisconnectWallpapers.add(mLastLockWallpaper); + } + if (mFallbackWallpaper != null && mFallbackWallpaper.connection != null + && mFallbackWallpaper.connection.containsDisplay(displayId)) { + pendingDisconnectWallpapers.add(mFallbackWallpaper); + } + for (int i = 0; i < pendingDisconnectWallpapers.size(); i++) { + WallpaperData wallpaper = pendingDisconnectWallpapers.get(i); + DisplayConnector displayConnector = + wallpaper.connection.getDisplayConnectorOrCreate(displayId); + if (displayConnector == null) { + Slog.w(TAG, + "Fail to disconnect wallpaper upon display removal"); + return; + } + displayConnector.disconnectLocked(wallpaper.connection); + wallpaper.connection.removeDisplayConnector(displayId); + } + } else { + if (mLastWallpaper != null) { + WallpaperData targetWallpaper = null; + if (mLastWallpaper.connection != null + && mLastWallpaper.connection.containsDisplay(displayId)) { + targetWallpaper = mLastWallpaper; + } else if (mFallbackWallpaper != null + && mFallbackWallpaper.connection != null + && mFallbackWallpaper.connection.containsDisplay( + displayId)) { + targetWallpaper = mFallbackWallpaper; + } + if (targetWallpaper == null) return; + DisplayConnector connector = + targetWallpaper.connection.getDisplayConnectorOrCreate( + displayId); + if (connector == null) return; + connector.disconnectLocked(targetWallpaper.connection); + targetWallpaper.connection.removeDisplayConnector(displayId); } - if (targetWallpaper == null) return; - DisplayConnector connector = - targetWallpaper.connection.getDisplayConnectorOrCreate(displayId); - if (connector == null) return; - connector.disconnectLocked(targetWallpaper.connection); - targetWallpaper.connection.removeDisplayConnector(displayId); - mWallpaperDisplayHelper.removeDisplayData(displayId); } + + mWallpaperDisplayHelper.removeDisplayData(displayId); + for (int i = mColorsChangedListeners.size() - 1; i >= 0; i--) { final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> callbacks = mColorsChangedListeners.valueAt(i); @@ -1627,6 +1668,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub public void onScreenTurnedOn(int displayId) { notifyScreenTurnedOn(displayId); } + @Override public void onScreenTurningOn(int displayId) { notifyScreenTurningOn(displayId); @@ -3707,6 +3749,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } if (newWallpaper.mWhich == (FLAG_SYSTEM | FLAG_LOCK)) { mLastWallpaper = newWallpaper; + mLastLockWallpaper = null; } else if (newWallpaper.mWhich == FLAG_SYSTEM) { mLastWallpaper = newWallpaper; } else if (newWallpaper.mWhich == FLAG_LOCK) { @@ -3916,13 +3959,49 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (mLastWallpaper == null) { return; } - if (supportsMultiDisplay(mLastWallpaper.connection)) { - final DisplayConnector connector = - mLastWallpaper.connection.getDisplayConnectorOrCreate(displayId); - if (connector == null) return; - connector.connectLocked(mLastWallpaper.connection, mLastWallpaper); - return; + if (enableConnectedDisplaysWallpaper()) { + int useFallbackWallpaperWhich = 0; + List<WallpaperData> wallpapers = new ArrayList<>(); + wallpapers.add(mLastWallpaper); + // If the system and the lock wallpapers are not the same, we should also + // establish a display connector to the lock wallpaper for this display. + if (mLastLockWallpaper != null && mLastWallpaper != mLastLockWallpaper) { + wallpapers.add(mLastLockWallpaper); + } + + for (int i = 0; i < wallpapers.size(); i++) { + WallpaperData wallpaper = wallpapers.get(i); + if (supportsMultiDisplay(wallpaper.connection)) { + final DisplayConnector connector = + wallpaper.connection.getDisplayConnectorOrCreate(displayId); + if (connector != null) { + connector.connectLocked(wallpaper.connection, wallpaper); + } else { + Slog.w(TAG, "Fail to connect to wallpaper for display id " + displayId + + " due to null connector. Use fallback wallpaper."); + useFallbackWallpaperWhich |= wallpaper.mWhich; + } + } else { + useFallbackWallpaperWhich |= wallpaper.mWhich; + } + } + + if (useFallbackWallpaperWhich == 0 + || mFallbackWallpaper == null + || mFallbackWallpaper.connection == null) { + return; + } + mFallbackWallpaper.mWhich = useFallbackWallpaperWhich; + } else { + if (supportsMultiDisplay(mLastWallpaper.connection)) { + final DisplayConnector connector = + mLastWallpaper.connection.getDisplayConnectorOrCreate(displayId); + if (connector == null) return; + connector.connectLocked(mLastWallpaper.connection, mLastWallpaper); + return; + } } + // System wallpaper does not support multiple displays, attach this display to // the fallback wallpaper. if (mFallbackWallpaper != null && mFallbackWallpaper diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index dd769173fb34..12f553426c80 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -58,7 +58,6 @@ import android.graphics.Matrix; import android.graphics.Path; import android.graphics.Point; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.Region; import android.os.Binder; import android.os.Build; @@ -69,7 +68,6 @@ import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.SystemClock; -import android.util.ArraySet; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -79,7 +77,6 @@ import android.view.Display; import android.view.MagnificationSpec; import android.view.Surface; import android.view.ViewConfiguration; -import android.view.WindowInfo; import android.view.WindowManager; import android.view.WindowManager.TransitionFlags; import android.view.WindowManager.TransitionType; @@ -557,9 +554,6 @@ final class AccessibilityController { private static final boolean DEBUG_WINDOW_TRANSITIONS = false; private static final boolean DEBUG_DISPLAY_SIZE = false; - private static final boolean DEBUG_LAYERS = false; - private static final boolean DEBUG_RECTANGLE_REQUESTED = false; - private static final boolean DEBUG_VIEWPORT_WINDOW = false; private final Rect mTempRect1 = new Rect(); private final Rect mTempRect2 = new Rect(); @@ -579,8 +573,6 @@ final class AccessibilityController { private final MagnificationCallbacks mCallbacks; private final UserContextChangedNotifier mUserContextChangedNotifier; - private final long mLongAnimationDuration; - private boolean mIsFullscreenMagnificationActivated = false; private final Region mMagnificationRegion = new Region(); private final Region mOldMagnificationRegion = new Region(); @@ -593,7 +585,6 @@ final class AccessibilityController { private final Point mScreenSize = new Point(); private final SparseArray<WindowState> mTempWindowStates = new SparseArray<WindowState>(); - private final RectF mTempRectF = new RectF(); private final Matrix mTempMatrix = new Matrix(); DisplayMagnifier(WindowManagerService windowManagerService, @@ -609,8 +600,6 @@ final class AccessibilityController { mUserContextChangedNotifier = new UserContextChangedNotifier(mHandler); mAccessibilityTracing = AccessibilityController.getAccessibilityControllerInternal(mService); - mLongAnimationDuration = mDisplayContext.getResources().getInteger( - com.android.internal.R.integer.config_longAnimTime); if (mDisplayContext.getResources().getConfiguration().isScreenRound()) { mCircularPath = new Path(); @@ -840,10 +829,6 @@ final class AccessibilityController { outMagnificationRegion.set(mMagnificationRegion); } - boolean isMagnifying() { - return mMagnificationSpec.scale > 1.0f; - } - void destroy() { if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) { mAccessibilityTracing.logTrace(LOG_TAG + ".destroy", FLAGS_MAGNIFICATION_CALLBACK); @@ -1172,12 +1157,6 @@ final class AccessibilityController { private static final boolean DEBUG = false; - private final Set<IBinder> mTempBinderSet = new ArraySet<>(); - - private final Region mTempRegion = new Region(); - - private final Region mTempRegion2 = new Region(); - private final WindowManagerService mService; private final Handler mHandler; @@ -1243,11 +1222,10 @@ final class AccessibilityController { Slog.i(LOG_TAG, "computeChangedWindows()"); } - List<WindowInfo> windows = null; final List<AccessibilityWindow> visibleWindows = new ArrayList<>(); final Point screenSize = new Point(); final int topFocusedDisplayId; - IBinder topFocusedWindowToken = null; + final IBinder topFocusedWindowToken; synchronized (mService.mGlobalLock) { final WindowState topFocusedWindowState = getTopFocusWindow(); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 8e4d4be693f8..c7d4467a6e98 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -103,6 +103,7 @@ import android.app.PendingIntent; import android.app.ProfilerInfo; import android.app.WaitResult; import android.app.WindowConfiguration; +import android.app.WindowConfiguration.WindowingMode; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; @@ -233,6 +234,7 @@ class ActivityStarter { // The task display area to launch the activity onto, barring any strong reason to do otherwise. private TaskDisplayArea mPreferredTaskDisplayArea; + @WindowingMode private int mPreferredWindowingMode; private Task mInTask; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 1bbae7f17308..a0d2d260b39e 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3261,9 +3261,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } mWmService.mDisplayWindowSettings.setShouldShowSystemDecorsLocked(this, shouldShow); - if (shouldShow) { - mRootWindowContainer.startSystemDecorations(this, "onDisplayInfoChangeApplied"); - } else { + if (!shouldShow) { clearAllTasksOnDisplay(null); } } @@ -6471,7 +6469,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return mRemoving; } - private void clearAllTasksOnDisplay(@Nullable Runnable clearTasksCallback) { + void clearAllTasksOnDisplay(@Nullable Runnable clearTasksCallback) { Task lastReparentedRootTask; mRootWindowContainer.mTaskSupervisor.beginDeferResume(); try { diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 319b48a89316..e1a50a93edcc 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -67,6 +67,7 @@ import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_SCREEN_ON; +import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement; import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; @@ -746,6 +747,31 @@ public class DisplayPolicy { return mHasNavigationBar; } + void updateHasNavigationBarIfNeeded() { + if (!enableDisplayContentModeManagement()) { + Slog.e(TAG, "mHasNavigationBar shouldn't be updated when the flag is off."); + } + + if (mDisplayContent.isDefaultDisplay) { + return; + } + + final boolean hasNavigationBar = mDisplayContent.isSystemDecorationsSupported(); + if (mHasNavigationBar == hasNavigationBar) { + return; + } + + mHasNavigationBar = hasNavigationBar; + mHandler.post( + () -> { + final int displayId = getDisplayId(); + StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); + if (statusBar != null) { + statusBar.setHasNavigationBar(displayId, mHasNavigationBar); + } + }); + } + public boolean hasStatusBar() { return mHasStatusBar; } @@ -1876,6 +1902,17 @@ public class DisplayPolicy { }); } + void notifyDisplayRemoveSystemDecorations() { + mHandler.post( + () -> { + final int displayId = getDisplayId(); + StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); + if (statusBar != null) { + statusBar.onDisplayRemoveSystemDecorations(displayId); + } + }); + } + /** * Return corner radius in pixels that should be used on windows in order to cover the display. * diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java index 4ae100857f55..28aa6eff911b 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java +++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java @@ -26,6 +26,8 @@ import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED; import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_AUTO; import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_DISABLED; +import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.WindowConfiguration; @@ -244,11 +246,27 @@ class DisplayWindowSettings { } void setShouldShowSystemDecorsLocked(@NonNull DisplayContent dc, boolean shouldShow) { + final boolean changed = (shouldShow != shouldShowSystemDecorsLocked(dc)); + final DisplayInfo displayInfo = dc.getDisplayInfo(); final SettingsProvider.SettingsEntry overrideSettings = mSettingsProvider.getOverrideSettings(displayInfo); overrideSettings.mShouldShowSystemDecors = shouldShow; mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings); + + if (enableDisplayContentModeManagement()) { + if (dc.isDefaultDisplay || dc.isPrivate() || !changed) { + return; + } + + dc.getDisplayPolicy().updateHasNavigationBarIfNeeded(); + + if (shouldShow) { + mService.mRoot.startSystemDecorations(dc, "setShouldShowSystemDecorsLocked"); + } else { + dc.getDisplayPolicy().notifyDisplayRemoveSystemDecorations(); + } + } } boolean isHomeSupportedLocked(@NonNull DisplayContent dc) { diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index 4bcba13448e9..f465c95addb7 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -899,7 +899,9 @@ class InsetsPolicy { } @Override - public void notifyAnimationRunningStateChanged(boolean running) { + public void notifyAnimationRunningStateChanged(boolean running, + @InsetsController.AnimationType int animationType, + @InsetsType int insetsTypes) { mInsetsAnimationRunning = running; } } diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java index ba1401ab3978..4f5c0c8ecf6e 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsController.java +++ b/services/core/java/com/android/server/wm/LaunchParamsController.java @@ -28,6 +28,7 @@ import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier. import android.annotation.IntDef; import android.annotation.Nullable; import android.app.ActivityOptions; +import android.app.WindowConfiguration.WindowingMode; import android.content.pm.ActivityInfo.WindowLayout; import android.graphics.Rect; @@ -186,6 +187,7 @@ class LaunchParamsController { TaskDisplayArea mPreferredTaskDisplayArea; /** The windowing mode to be in. */ + @WindowingMode int mWindowingMode; /** Sets values back to default. {@link #isEmpty} will return {@code true} once called. */ diff --git a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java index efc68aac0323..00e1c01bbadb 100644 --- a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java +++ b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java @@ -22,6 +22,7 @@ import static com.android.internal.protolog.WmProtoLogGroups.WM_ERROR; import android.media.projection.IMediaProjectionManager; import android.media.projection.IMediaProjectionWatcherCallback; +import android.media.projection.MediaProjectionEvent; import android.media.projection.MediaProjectionInfo; import android.os.Binder; import android.os.IBinder; @@ -84,6 +85,12 @@ public class ScreenRecordingCallbackController { public void onRecordingSessionSet(MediaProjectionInfo mediaProjectionInfo, ContentRecordingSession contentRecordingSession) { } + + @Override + public void onMediaProjectionEvent( + MediaProjectionEvent event, + MediaProjectionInfo mediaProjectionInfo, + ContentRecordingSession session) {} } ScreenRecordingCallbackController(WindowManagerService wms) { diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 0ecd0251ca94..3b79c54f1c73 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -89,8 +89,9 @@ class WallpaperWindowToken extends WindowToken { // Similar to Task.prepareSurfaces, outside of transitions we need to apply visibility // changes directly. In transitions the transition player will take care of applying the // visibility change. - if (!mTransitionController.inTransition(this)) { - getSyncTransaction().setVisibility(mSurfaceControl, isVisible()); + if (!mTransitionController.isCollecting(this) + && !mTransitionController.isPlayingTarget(this)) { + getPendingTransaction().setVisibility(mSurfaceControl, isVisible()); } } } diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index c77b1d9a7bcf..7a8230f1f963 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -41,6 +41,7 @@ import android.view.Display; import android.view.IInputFilter; import android.view.IRemoteAnimationFinishedCallback; import android.view.IWindow; +import android.view.InsetsController; import android.view.MagnificationSpec; import android.view.RemoteAnimationTarget; import android.view.Surface; @@ -469,6 +470,24 @@ public abstract class WindowManagerInternal { public abstract void getMagnificationRegion(int displayId, @NonNull Region magnificationRegion); /** + * Set by the autofill service to observe changes in the ime animations. + * + * @param listener The callbacks to invoke. + */ + public abstract void setImeInsetsAnimationChangeListener( + @Nullable ImeInsetsAnimationChangeListener listener); + + /** Listener for changes in ime insets animation */ + public interface ImeInsetsAnimationChangeListener { + + /** Notify on start of animation */ + void onAnimationStart(@InsetsController.AnimationType int animationType, int userId); + + /** Notify on end of animation */ + void onAnimationEnd(@InsetsController.AnimationType int animationType, int userId); + } + + /** * Sets a callback for observing which windows are touchable for the purposes * of accessibility on specified display. * diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 5de0e9b6ed93..28ea3b0bf6ba 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.service.autofill.Flags.improveFillDialogAconfig; import static android.Manifest.permission.ACCESS_SURFACE_FLINGER; import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; import static android.Manifest.permission.INPUT_CONSUMER; @@ -277,6 +278,7 @@ import android.view.InputApplicationHandle; import android.view.InputChannel; import android.view.InputDevice; import android.view.InputWindowHandle; +import android.view.InsetsController; import android.view.InsetsFrameProvider; import android.view.InsetsSourceControl; import android.view.InsetsState; @@ -309,6 +311,7 @@ import android.window.ActivityWindowInfo; import android.window.AddToSurfaceSyncGroupResult; import android.window.ClientWindowFrames; import android.window.ConfigurationChangeSetting; +import android.window.DesktopModeFlags; import android.window.IGlobalDragListener; import android.window.IScreenRecordingCallback; import android.window.ISurfaceSyncGroupCompletedListener; @@ -792,6 +795,9 @@ public class WindowManagerService extends IWindowManager.Stub final TrustedPresentationListenerController mTrustedPresentationListenerController = new TrustedPresentationListenerController(); + private WindowManagerInternal.ImeInsetsAnimationChangeListener + mImeInsetsAnimationChangeListener; + @VisibleForTesting final class SettingsObserver extends ContentObserver { private final Uri mDisplayInversionEnabledUri = @@ -820,6 +826,8 @@ public class WindowManagerService extends IWindowManager.Stub DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH); private final Uri mMaximumObscuringOpacityForTouchUri = Settings.Global.getUriFor( Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH); + private final Uri mDevelopmentOverrideDesktopExperienceUri = Settings.Global.getUriFor( + Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_EXPERIENCE_FEATURES); public SettingsObserver() { super(new Handler()); @@ -847,6 +855,8 @@ public class WindowManagerService extends IWindowManager.Stub UserHandle.USER_ALL); resolver.registerContentObserver(mMaximumObscuringOpacityForTouchUri, false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(mDevelopmentOverrideDesktopExperienceUri, false, this, + UserHandle.USER_ALL); } @Override @@ -890,6 +900,11 @@ public class WindowManagerService extends IWindowManager.Stub return; } + if (mDevelopmentOverrideDesktopExperienceUri.equals(uri)) { + updateDevelopmentOverrideDesktopExperience(); + return; + } + @UpdateAnimationScaleMode final int mode; if (mWindowAnimationScaleUri.equals(uri)) { @@ -956,6 +971,16 @@ public class WindowManagerService extends IWindowManager.Stub mAtmService.mForceResizableActivities = forceResizable; } + void updateDevelopmentOverrideDesktopExperience() { + ContentResolver resolver = mContext.getContentResolver(); + final int overrideDesktopMode = Settings.Global.getInt(resolver, + Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_EXPERIENCE_FEATURES, + DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET.getSetting()); + + SystemProperties.set(DesktopModeFlags.SYSTEM_PROPERTY_NAME, + Integer.toString(overrideDesktopMode)); + } + void updateDevEnableNonResizableMultiWindow() { ContentResolver resolver = mContext.getContentResolver(); final boolean devEnableNonResizableMultiWindow = Settings.Global.getInt(resolver, @@ -8602,6 +8627,14 @@ public class WindowManagerService extends IWindowManager.Stub // WMS.takeAssistScreenshot takes care of the locking. return WindowManagerService.this.takeAssistScreenshot(windowTypesToExclude); } + + @Override + public void setImeInsetsAnimationChangeListener( + @Nullable WindowManagerInternal.ImeInsetsAnimationChangeListener listener) { + synchronized (mGlobalLock) { + mImeInsetsAnimationChangeListener = listener; + } + } } private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy { @@ -10159,6 +10192,24 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public void notifyImeInsetsAnimationStateChanged( + boolean running, @InsetsController.AnimationType int animationType) { + if (improveFillDialogAconfig()) { + synchronized (mGlobalLock) { + if (mImeInsetsAnimationChangeListener == null) { + return; + } + if (running) { + mImeInsetsAnimationChangeListener.onAnimationStart( + animationType, mCurrentUserId); + } else { + mImeInsetsAnimationChangeListener.onAnimationEnd(animationType, mCurrentUserId); + } + } + } + } + boolean getDisableSecureWindows() { return mDisableSecureWindows; } diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp index 6393e11b7432..1db9e8d545e4 100644 --- a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp +++ b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp @@ -1,7 +1,7 @@ aconfig_declarations { name: "device_state_flags", package: "com.android.server.policy.feature.flags", - container: "system", + container: "system_ext", srcs: [ "device_state_flags.aconfig", ], diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig index da2e5ee37c1a..bbbbe5db91dd 100644 --- a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig +++ b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig @@ -1,5 +1,5 @@ package: "com.android.server.policy.feature.flags" -container: "system" +container: "system_ext" flag { name: "enable_dual_display_blocking" diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 25e9f8a38f89..c974d9e1dc87 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1799,7 +1799,7 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startService(LogcatManagerService.class); t.traceEnd(); - if (!isWatch && !isTv && !isAutomotive + if (!isWatch && !isTv && !isAutomotive && !isDesktop && android.security.Flags.aflApi()) { t.traceBegin("StartIntrusionDetectionService"); mSystemServiceManager.startService(IntrusionDetectionService.class); diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayBackupHelperTest.kt b/services/tests/displayservicetests/src/com/android/server/display/DisplayBackupHelperTest.kt new file mode 100644 index 000000000000..26060a406aa0 --- /dev/null +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayBackupHelperTest.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display + +import androidx.test.filters.SmallTest +import android.hardware.display.DisplayManagerInternal +import android.util.AtomicFileOutputStream +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever +import org.mockito.kotlin.verify +import org.mockito.kotlin.never + +@SmallTest +class DisplayBackupHelperTest { + private val mockInjector = mock<DisplayBackupHelper.Injector>() + private val mockDmsInternal = mock<DisplayManagerInternal>() + private val mockWriteTopologyFile = mock<AtomicFileOutputStream>() + private val byteArray = byteArrayOf(0b00000001, 0b00000010, 0b00000011) + private val helper = createBackupHelper(0, byteArray) + + @Test + fun testBackupDisplayReturnsBytes() { + assertThat(helper.getBackupPayload("display")).isEqualTo(byteArray) + } + + @Test + fun testBackupSomethingReturnsNull() { + assertThat(helper.getBackupPayload("something")).isNull() + } + + @Test + fun testBackupDisplayReturnsNullWhenFlagDisabled() { + whenever(mockInjector.isDisplayTopologyFlagEnabled()).thenReturn(false) + assertThat(helper.getBackupPayload("display")).isNull() + } + + @Test + fun testRestoreDisplay() { + helper.applyRestoredPayload("display", byteArray) + verify(mockWriteTopologyFile).write(byteArray) + verify(mockWriteTopologyFile).markSuccess() + verify(mockDmsInternal).reloadTopologies(0) + } + + @Test + fun testRestoreSomethingDoesNothing() { + helper.applyRestoredPayload("something", byteArray) + verify(mockWriteTopologyFile, never()).write(byteArray) + verify(mockWriteTopologyFile, never()).markSuccess() + verify(mockDmsInternal, never()).reloadTopologies(0) + } + + @Test + fun testRestoreDisplayDoesNothingWhenFlagDisabled() { + whenever(mockInjector.isDisplayTopologyFlagEnabled()).thenReturn(false) + helper.applyRestoredPayload("display", byteArray) + verify(mockWriteTopologyFile, never()).write(byteArray) + verify(mockWriteTopologyFile, never()).markSuccess() + verify(mockDmsInternal, never()).reloadTopologies(0) + } + + fun createBackupHelper(userId: Int, topologyToBackup: ByteArray): DisplayBackupHelper { + whenever(mockInjector.getDisplayManagerInternal()).thenReturn(mockDmsInternal) + whenever(mockInjector.readTopologyFile(userId)).thenReturn(topologyToBackup) + whenever(mockInjector.writeTopologyFile(userId)).thenReturn(mockWriteTopologyFile) + whenever(mockInjector.isDisplayTopologyFlagEnabled()).thenReturn(true) + + return DisplayBackupHelper(userId, mockInjector) + } +}
\ No newline at end of file diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index e8b28ac19a85..a0e18ff15770 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -31,6 +31,7 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_C import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; +import static android.hardware.display.DisplayManagerGlobal.INTERNAL_EVENT_FLAG_TOPOLOGY_UPDATED; import static android.hardware.display.HdrConversionMode.HDR_CONVERSION_SYSTEM; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; import static android.provider.Settings.Secure.MIRROR_BUILT_IN_DISPLAY; @@ -413,6 +414,9 @@ public class DisplayManagerServiceTest { .setStrictness(Strictness.LENIENT) .spyStatic(SystemProperties.class) .build(); + + private int mUniqueIdCount = 0; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -759,6 +763,83 @@ public class DisplayManagerServiceTest { } @Test + public void testCreateVirtualDisplayStealTopFocusDisabled() throws RemoteException { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + registerDefaultDisplays(displayManager); + + // This is effectively the DisplayManager service published to ServiceManager. + DisplayManagerService.BinderService bs = displayManager.new BinderService(); + + String uniqueId = "uniqueId --- Steal Top Focus Test"; + int width = 600; + int height = 800; + int dpi = 320; + int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED + | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS + | DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; + + when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn( + PackageManager.PERMISSION_GRANTED); + when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); + final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( + VIRTUAL_DISPLAY_NAME, width, height, dpi); + builder.setFlags(flags); + builder.setUniqueId(uniqueId); + int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken, + /* projection= */ null, PACKAGE_NAME); + verify(mMockProjectionService, never()).setContentRecordingSession(any(), + nullable(IMediaProjection.class)); + + performTraversalInternal(displayManager); + + // flush the handler + displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0); + + DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId); + assertNotNull(ddi); + assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_STEAL_TOP_FOCUS_DISABLED) != 0); + } + + @Test + public void testCreateVirtualDisplayOwnFocus_nonOwnFocusDisplay() throws RemoteException { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + registerDefaultDisplays(displayManager); + + // This is effectively the DisplayManager service published to ServiceManager. + DisplayManagerService.BinderService bs = displayManager.new BinderService(); + + String uniqueId = "uniqueId --- Steal Top Focus Test -- nonOwnFocusDisplay"; + int width = 600; + int height = 800; + int dpi = 320; + int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED + | DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; + + when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn( + PackageManager.PERMISSION_GRANTED); + when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); + final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( + VIRTUAL_DISPLAY_NAME, width, height, dpi); + builder.setFlags(flags); + builder.setUniqueId(uniqueId); + int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken, + /* projection= */ null, PACKAGE_NAME); + verify(mMockProjectionService, never()).setContentRecordingSession(any(), + nullable(IMediaProjection.class)); + + performTraversalInternal(displayManager); + + // flush the handler + displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0); + + DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId); + assertNotNull(ddi); + assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_STEAL_TOP_FOCUS_DISABLED) == 0); + } + + @Test public void testCreateVirtualDisplayOwnFocus_checkDisplayDeviceInfo() throws RemoteException { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); @@ -2126,11 +2207,12 @@ public class DisplayManagerServiceTest { @Test public void test_displayChangedNotified_displayInfoFramerateOverridden() { + when(mMockFlags.isFramerateOverrideTriggersRrCallbacksEnabled()).thenReturn(false); + DisplayManagerService displayManager = - new DisplayManagerService(mContext, mShortMockedInjector); + new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService displayManagerBinderService = displayManager.new BinderService(); - when(mMockFlags.isFramerateOverrideTriggersRrCallbacksEnabled()).thenReturn(false); registerDefaultDisplays(displayManager); displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); @@ -3786,6 +3868,7 @@ public class DisplayManagerServiceTest { public void testSetDisplayTopology() { manageDisplaysPermission(/* granted= */ true); when(mMockFlags.isDisplayTopologyEnabled()).thenReturn(true); + when(mMockFlags.isDisplayContentModeManagementEnabled()).thenReturn(true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerInternal localService = displayManager.new LocalService(); DisplayManagerService.BinderService displayManagerBinderService = @@ -3814,6 +3897,7 @@ public class DisplayManagerServiceTest { public void testShouldNotifyTopologyChanged() { manageDisplaysPermission(/* granted= */ true); when(mMockFlags.isDisplayTopologyEnabled()).thenReturn(true); + when(mMockFlags.isDisplayContentModeManagementEnabled()).thenReturn(true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService displayManagerBinderService = displayManager.new BinderService(); @@ -3822,19 +3906,22 @@ public class DisplayManagerServiceTest { FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(); displayManagerBinderService.registerCallbackWithEventMask(callback, - DisplayManagerGlobal.INTERNAL_EVENT_FLAG_TOPOLOGY_UPDATED); + INTERNAL_EVENT_FLAG_TOPOLOGY_UPDATED); waitForIdleHandler(handler); - displayManagerBinderService.setDisplayTopology(new DisplayTopology()); - waitForIdleHandler(handler); - - assertThat(callback.receivedEvents()).containsExactly(TOPOLOGY_CHANGED_EVENT); + var topology = initDisplayTopology(displayManager, displayManagerBinderService, callback, + handler, /*shouldEmitTopologyChangeEvent=*/ true); + callback.clear(); + callback.expectsEvent(TOPOLOGY_CHANGED_EVENT); + displayManagerBinderService.setDisplayTopology(topology); + callback.waitForExpectedEvent(); } @Test public void testShouldNotNotifyTopologyChanged_WhenClientIsNotSubscribed() { manageDisplaysPermission(/* granted= */ true); when(mMockFlags.isDisplayTopologyEnabled()).thenReturn(true); + when(mMockFlags.isDisplayContentModeManagementEnabled()).thenReturn(true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService displayManagerBinderService = displayManager.new BinderService(); @@ -3847,9 +3934,13 @@ public class DisplayManagerServiceTest { STANDARD_DISPLAY_EVENTS); waitForIdleHandler(handler); - displayManagerBinderService.setDisplayTopology(new DisplayTopology()); + var topology = initDisplayTopology(displayManager, displayManagerBinderService, callback, + handler, /*shouldEmitTopologyChangeEvent=*/ false); + callback.clear(); + callback.expectsEvent(TOPOLOGY_CHANGED_EVENT); // should not happen + displayManagerBinderService.setDisplayTopology(topology); + callback.waitForNonExpectedEvent(); // checks that event did not happen waitForIdleHandler(handler); - assertThat(callback.receivedEvents()).isEmpty(); } @@ -4527,6 +4618,7 @@ public class DisplayManagerServiceTest { new float[0], new int[0]); } displayDeviceInfo.name = "" + displayType; + displayDeviceInfo.uniqueId = "uniqueId" + mUniqueIdCount++; displayDeviceInfo.modeId = 1; displayDeviceInfo.type = displayType; displayDeviceInfo.renderFrameRate = displayDeviceInfo.supportedModes[0].getRefreshRate(); @@ -4599,6 +4691,42 @@ public class DisplayManagerServiceTest { } } + private DisplayTopology initDisplayTopology(DisplayManagerService displayManager, + DisplayManagerService.BinderService displayManagerBinderService, + FakeDisplayManagerCallback callback, + Handler handler, boolean shouldEmitTopologyChangeEvent) { + Settings.Global.putInt(mContext.getContentResolver(), + DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 1); + callback.expectsEvent(TOPOLOGY_CHANGED_EVENT); + FakeDisplayDevice displayDevice0 = + createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL); + int displayId0 = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService, + displayDevice0); + if (shouldEmitTopologyChangeEvent) { + callback.waitForExpectedEvent(); + } else { + callback.waitForNonExpectedEvent(); + } + callback.clear(); + + callback.expectsEvent(TOPOLOGY_CHANGED_EVENT); + FakeDisplayDevice displayDevice1 = createFakeDisplayDevice(displayManager, + new float[]{60f}, Display.TYPE_OVERLAY); + int displayId1 = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService, + displayDevice1); + waitForIdleHandler(handler); + if (shouldEmitTopologyChangeEvent) { + callback.waitForExpectedEvent(); + } else { + callback.waitForNonExpectedEvent(); + } + + var topology = new DisplayTopology(); + topology.addDisplay(displayId0, 2048, 800); + topology.addDisplay(displayId1, 1920, 1080); + return topology; + } + private static class FakeDisplayManagerCallback extends IDisplayManagerCallback.Stub implements DisplayManagerInternal.DisplayGroupListener { int mDisplayId; diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt index b09947aaf2ad..04dff1d36495 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt @@ -18,6 +18,7 @@ package com.android.server.display import android.hardware.display.DisplayTopology import android.hardware.display.DisplayTopology.pxToDp +import android.util.SparseArray import android.view.Display import android.view.DisplayInfo import com.google.common.truth.Truth.assertThat @@ -37,9 +38,11 @@ class DisplayTopologyCoordinatorTest { private val displayInfo = DisplayInfo() private val topologyChangeExecutor = Runnable::run + private val mockTopologyStore = mock<DisplayTopologyStore>() private val mockTopology = mock<DisplayTopology>() private val mockTopologyCopy = mock<DisplayTopology>() private val mockIsExtendedDisplayEnabled = mock<() -> Boolean>() + private val mockTopologySavedCallback = mock<() -> Unit>() private val mockTopologyChangedCallback = mock<(DisplayTopology) -> Unit>() @Before @@ -51,11 +54,17 @@ class DisplayTopologyCoordinatorTest { val injector = object : DisplayTopologyCoordinator.Injector() { override fun getTopology() = mockTopology + override fun createTopologyStore( + displayIdToUniqueId: SparseArray<String>, + uniqueIdToDisplayId: MutableMap<String, Int> + ) = + mockTopologyStore } whenever(mockIsExtendedDisplayEnabled()).thenReturn(true) whenever(mockTopology.copy()).thenReturn(mockTopologyCopy) coordinator = DisplayTopologyCoordinator(injector, mockIsExtendedDisplayEnabled, - mockTopologyChangedCallback, topologyChangeExecutor, DisplayManagerService.SyncRoot()) + mockTopologyChangedCallback, topologyChangeExecutor, DisplayManagerService.SyncRoot(), + mockTopologySavedCallback) } @Test @@ -66,6 +75,7 @@ class DisplayTopologyCoordinatorTest { val heightDp = pxToDp(displayInfo.logicalHeight.toFloat(), displayInfo.logicalDensityDpi) verify(mockTopology).addDisplay(displayInfo.displayId, widthDp, heightDp) verify(mockTopologyChangedCallback).invoke(mockTopologyCopy) + verify(mockTopologyStore).restoreTopology(mockTopology) } @Test @@ -76,6 +86,7 @@ class DisplayTopologyCoordinatorTest { verify(mockTopology, never()).addDisplay(anyInt(), anyFloat(), anyFloat()) verify(mockTopologyChangedCallback, never()).invoke(any()) + verify(mockTopologyStore, never()).restoreTopology(any()) } @Test @@ -86,6 +97,7 @@ class DisplayTopologyCoordinatorTest { verify(mockTopology, never()).addDisplay(anyInt(), anyFloat(), anyFloat()) verify(mockTopologyChangedCallback, never()).invoke(any()) + verify(mockTopologyStore, never()).restoreTopology(any()) } @Test @@ -115,6 +127,7 @@ class DisplayTopologyCoordinatorTest { coordinator.onDisplayRemoved(Display.DEFAULT_DISPLAY) verify(mockTopologyChangedCallback).invoke(mockTopologyCopy) + verify(mockTopologyStore).restoreTopology(mockTopology) } @Test @@ -124,6 +137,7 @@ class DisplayTopologyCoordinatorTest { coordinator.onDisplayRemoved(Display.DEFAULT_DISPLAY) verify(mockTopologyChangedCallback, never()).invoke(any()) + verify(mockTopologyStore, never()).restoreTopology(any()) } @Test @@ -136,10 +150,12 @@ class DisplayTopologyCoordinatorTest { val topology = mock<DisplayTopology>() val topologyCopy = mock<DisplayTopology>() whenever(topology.copy()).thenReturn(topologyCopy) - + whenever(mockTopologyStore.saveTopology(topology)).thenReturn(true) coordinator.topology = topology verify(topology).normalize() verify(mockTopologyChangedCallback).invoke(topologyCopy) + verify(mockTopologyStore).saveTopology(topology) + verify(mockTopologySavedCallback).invoke() } }
\ No newline at end of file diff --git a/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java index 439243e85e75..6e9a28f344e3 100644 --- a/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java +++ b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java @@ -139,8 +139,8 @@ public class AudioManagerRouteControllerTest { mMockAudioManager, Looper.getMainLooper(), mMediaAudioProductStrategy, - btAdapter, - mOnDeviceRouteChangedListener); + btAdapter); + mControllerUnderTest.registerRouteChangeListener(mOnDeviceRouteChangedListener); mControllerUnderTest.start(UserHandle.CURRENT_OR_SELF); ArgumentCaptor<AudioDeviceCallback> deviceCallbackCaptor = diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java index 7e179095d99b..86bf203771ba 100644 --- a/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java @@ -93,7 +93,8 @@ public class SystemBackupAgentTest { "app_locales", "app_gender", "companion", - "system_gender"); + "system_gender", + "display"); } @Test @@ -118,7 +119,8 @@ public class SystemBackupAgentTest { "app_locales", "app_gender", "companion", - "system_gender"); + "system_gender", + "display"); } @Test @@ -136,7 +138,8 @@ public class SystemBackupAgentTest { "app_locales", "companion", "app_gender", - "system_gender"); + "system_gender", + "display"); } @Test @@ -158,7 +161,8 @@ public class SystemBackupAgentTest { "shortcut_manager", "companion", "app_gender", - "system_gender"); + "system_gender", + "display"); } @Test diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java index 8a10040f986f..8dc657ed75a6 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java @@ -49,6 +49,7 @@ import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.KeyguardManager; +import android.app.PropertyInvalidatedCache; import android.content.Context; import android.content.pm.PackageManagerInternal; import android.content.pm.UserInfo; @@ -181,8 +182,8 @@ public final class UserManagerServiceTest { MockitoAnnotations.initMocks(this); mSpiedContext = spy(mRealContext); - // Called when WatchedUserStates is constructed - doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache()); + // Disable binder caches in this process. + PropertyInvalidatedCache.disableForTestMode(); // Called when creating new users when(mDeviceStorageMonitorInternal.isMemoryLow()).thenReturn(false); diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java index db323f1b68e7..1cf655675a30 100644 --- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java @@ -33,6 +33,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertEquals; @@ -65,6 +66,7 @@ import android.content.pm.ParceledListSlice; import android.content.pm.ServiceInfo; import android.graphics.Color; import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.RemoteException; @@ -75,6 +77,7 @@ import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.service.wallpaper.IWallpaperConnection; import android.service.wallpaper.IWallpaperEngine; +import android.service.wallpaper.IWallpaperService; import android.service.wallpaper.WallpaperService; import android.testing.TestableContext; import android.util.Log; @@ -105,6 +108,7 @@ import org.junit.Test; import org.junit.rules.RuleChain; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.quality.Strictness; @@ -154,6 +158,8 @@ public class WallpaperManagerServiceTests { private WallpaperManagerService mService; private static IWallpaperConnection.Stub sWallpaperService; + private static WindowManagerInternal sWindowManagerInternal; + @BeforeClass public static void setUpClass() { sMockitoSession = mockitoSession() @@ -163,8 +169,8 @@ public class WallpaperManagerServiceTests { .spyStatic(WallpaperManager.class) .startMocking(); - final WindowManagerInternal dmi = mock(WindowManagerInternal.class); - LocalServices.addService(WindowManagerInternal.class, dmi); + sWindowManagerInternal = mock(WindowManagerInternal.class); + LocalServices.addService(WindowManagerInternal.class, sWindowManagerInternal); sContext.addMockSystemService(Context.APP_OPS_SERVICE, mock(AppOpsManager.class)); @@ -336,6 +342,43 @@ public class WallpaperManagerServiceTests { } /** + * Test setWallpaperComponent with FLAG_LOCK should update the mLastLockWallpaper. + */ + @Test + public void testSetLockWallpaper() { + final int testUserId = USER_SYSTEM; + mService.switchUser(testUserId, null); + verifyLastWallpaperData(testUserId, sDefaultWallpaperComponent); + verifyCurrentSystemData(testUserId); + + mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(), + FLAG_LOCK, testUserId); + verifyLastLockWallpaperData(testUserId, sImageWallpaperComponentName); + verifyCurrentSystemData(testUserId); + } + + /** + * Test setWallpaperComponent with FLAG_LOCK and then setWallpaperComponent with + * FLAG_LOCK | FLAG_SYSTEM should set mLastLockWallpaper to null. + */ + @Test + public void testSetLockWallpaperThenSetLockAndSystemWallpaper_setLastLockWallpaperToNull() { + final int testUserId = USER_SYSTEM; + mService.switchUser(testUserId, null); + verifyLastWallpaperData(testUserId, sDefaultWallpaperComponent); + verifyCurrentSystemData(testUserId); + + mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(), + FLAG_LOCK, testUserId); + mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(), + FLAG_LOCK | FLAG_SYSTEM, testUserId); + + verifyLastWallpaperData(testUserId, sImageWallpaperComponentName); + assertThat(mService.mLastLockWallpaper).isNull(); + verifyCurrentSystemData(testUserId); + } + + /** * Tests that when setWallpaperComponent is called with the currently set component, a command * is issued to the wallpaper. */ @@ -661,6 +704,171 @@ public class WallpaperManagerServiceTests { assertPfdAndFileContentsEqual(pfd, originalSystemWallpaperFile); } + // Verify a secondary display added started + @Test + @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER) + public void displayAdded_sameSystemAndLockWallpaper_shouldAttachWallpaperServiceOnce() + throws Exception { + // GIVEN the same wallpaper used for the lock and system. + final int testUserId = USER_SYSTEM; + mService.switchUser(testUserId, null); + final WallpaperData wallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM, testUserId); + IWallpaperService mockIWallpaperService = mock(IWallpaperService.class); + wallpaper.connection.mService = mockIWallpaperService; + // GIVEN there are two displays: DEFAULT_DISPLAY, 2 + final int testDisplayId = 2; + setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); + + // WHEN displayId, 2, is ready. + WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( + WallpaperManagerInternal.class); + wallpaperManagerInternal.onDisplayReady(testDisplayId); + + // Then there is a connection established for the system & lock wallpaper for display ID, 2. + verify(mockIWallpaperService).attach( + /* connection= */ eq(wallpaper.connection), + /* windowToken= */ any(), + /* windowType= */ anyInt(), + /* isPreview= */ anyBoolean(), + /* reqWidth= */ anyInt(), + /* reqHeight= */ anyInt(), + /* padding= */ any(), + /* displayId= */ eq(testDisplayId), + /* which= */ eq(FLAG_SYSTEM | FLAG_LOCK), + /* info= */ any(), + /* description= */ any()); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER) + public void displayAdded_differentSystemAndLockWallpapers_shouldAttachWallpaperServiceTwice() + throws Exception { + // GIVEN different wallpapers used for the lock and system. + final int testUserId = USER_SYSTEM; + mService.switchUser(testUserId, null); + mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(), + FLAG_LOCK, testUserId); + final WallpaperData systemWallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM, + testUserId); + final WallpaperData lockWallpaper = mService.getCurrentWallpaperData(FLAG_LOCK, + testUserId); + IWallpaperService mockIWallpaperService = mock(IWallpaperService.class); + systemWallpaper.connection.mService = mockIWallpaperService; + lockWallpaper.connection.mService = mockIWallpaperService; + // GIVEN there are two displays: DEFAULT_DISPLAY, 2 + final int testDisplayId = 2; + setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); + + // WHEN displayId, 2, is ready. + WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( + WallpaperManagerInternal.class); + wallpaperManagerInternal.onDisplayReady(testDisplayId); + + // Then there is a connection established for the system wallpaper for display ID, 2. + verify(mockIWallpaperService).attach( + /* connection= */ eq(systemWallpaper.connection), + /* windowToken= */ any(), + /* windowType= */ anyInt(), + /* isPreview= */ anyBoolean(), + /* reqWidth= */ anyInt(), + /* reqHeight= */ anyInt(), + /* padding= */ any(), + /* displayId= */ eq(testDisplayId), + /* which= */ eq(FLAG_SYSTEM), + /* info= */ any(), + /* description= */ any()); + // Then there is a connection established for the lock wallpaper for display ID, 2. + verify(mockIWallpaperService).attach( + /* connection= */ eq(lockWallpaper.connection), + /* windowToken= */ any(), + /* windowType= */ anyInt(), + /* isPreview= */ anyBoolean(), + /* reqWidth= */ anyInt(), + /* reqHeight= */ anyInt(), + /* padding= */ any(), + /* displayId= */ eq(testDisplayId), + /* which= */ eq(FLAG_LOCK), + /* info= */ any(), + /* description= */ any()); + } + // Verify a secondary display added end + + // Verify a secondary display removed started + @Test + @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER) + public void displayRemoved_sameSystemAndLockWallpaper_shouldDetachWallpaperServiceOnce() + throws Exception { + ArgumentCaptor<DisplayListener> displayListenerCaptor = ArgumentCaptor.forClass( + DisplayListener.class); + verify(mDisplayManager).registerDisplayListener(displayListenerCaptor.capture(), eq(null)); + // GIVEN the same wallpaper used for the lock and system. + final int testUserId = USER_SYSTEM; + mService.switchUser(testUserId, null); + final WallpaperData wallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM, testUserId); + IWallpaperService mockIWallpaperService = mock(IWallpaperService.class); + wallpaper.connection.mService = mockIWallpaperService; + // GIVEN there are two displays: DEFAULT_DISPLAY, 2 + final int testDisplayId = 2; + setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); + // GIVEN wallpaper connections have been established for displayID, 2. + WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( + WallpaperManagerInternal.class); + wallpaperManagerInternal.onDisplayReady(testDisplayId); + // Save displayConnector for displayId 2 before display removal. + WallpaperManagerService.DisplayConnector displayConnector = + wallpaper.connection.getDisplayConnectorOrCreate(testDisplayId); + + // WHEN displayId, 2, is removed. + DisplayListener displayListener = displayListenerCaptor.getValue(); + displayListener.onDisplayRemoved(testDisplayId); + + // Then the wallpaper connection for displayId, 2, is detached. + verify(mockIWallpaperService).detach(eq(displayConnector.mToken)); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WALLPAPER) + public void displayRemoved_differentSystemAndLockWallpapers_shouldDetachWallpaperServiceTwice() + throws Exception { + ArgumentCaptor<DisplayListener> displayListenerCaptor = ArgumentCaptor.forClass( + DisplayListener.class); + verify(mDisplayManager).registerDisplayListener(displayListenerCaptor.capture(), eq(null)); + // GIVEN different wallpapers used for the lock and system. + final int testUserId = USER_SYSTEM; + mService.switchUser(testUserId, null); + mService.setWallpaperComponent(sImageWallpaperComponentName, sContext.getOpPackageName(), + FLAG_LOCK, testUserId); + final WallpaperData systemWallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM, + testUserId); + final WallpaperData lockWallpaper = mService.getCurrentWallpaperData(FLAG_LOCK, + testUserId); + IWallpaperService mockIWallpaperService = mock(IWallpaperService.class); + systemWallpaper.connection.mService = mockIWallpaperService; + lockWallpaper.connection.mService = mockIWallpaperService; + // GIVEN there are two displays: DEFAULT_DISPLAY, 2 + final int testDisplayId = 2; + setUpDisplays(List.of(DEFAULT_DISPLAY, testDisplayId)); + // GIVEN wallpaper connections have been established for displayID, 2. + WallpaperManagerInternal wallpaperManagerInternal = LocalServices.getService( + WallpaperManagerInternal.class); + wallpaperManagerInternal.onDisplayReady(testDisplayId); + // Save displayConnectors for displayId 2 before display removal. + WallpaperManagerService.DisplayConnector systemWallpaperDisplayConnector = + systemWallpaper.connection.getDisplayConnectorOrCreate(testDisplayId); + WallpaperManagerService.DisplayConnector lockWallpaperDisplayConnector = + lockWallpaper.connection.getDisplayConnectorOrCreate(testDisplayId); + + // WHEN displayId, 2, is removed. + DisplayListener displayListener = displayListenerCaptor.getValue(); + displayListener.onDisplayRemoved(testDisplayId); + + // Then the system wallpaper connection for displayId, 2, is detached. + verify(mockIWallpaperService).detach(eq(systemWallpaperDisplayConnector.mToken)); + // Then the lock wallpaper connection for displayId, 2, is detached. + verify(mockIWallpaperService).detach(eq(lockWallpaperDisplayConnector.mToken)); + } + // Verify a secondary display removed ended + // Verify that after continue switch user from userId 0 to lastUserId, the wallpaper data for // non-current user must not bind to wallpaper service. private void verifyNoConnectionBeforeLastUser(int lastUserId) { @@ -681,11 +889,31 @@ public class WallpaperManagerServiceTests { lastData.connection); } + private void verifyLastLockWallpaperData(int lastUserId, ComponentName expectedComponent) { + final WallpaperData lastLockData = mService.mLastLockWallpaper; + assertWithMessage("Last wallpaper must not be null").that(lastLockData).isNotNull(); + assertWithMessage("Last wallpaper component must be equals.") + .that(expectedComponent) + .isEqualTo(lastLockData.getComponent()); + assertWithMessage("The user id in last wallpaper should be the last switched user") + .that(lastUserId) + .isEqualTo(lastLockData.userId); + assertWithMessage("Must exist user data connection on last wallpaper data") + .that(lastLockData.connection) + .isNotNull(); + } + private void verifyCurrentSystemData(int userId) { final WallpaperData lastData = mService.mLastWallpaper; final WallpaperData wallpaper = mService.getCurrentWallpaperData(FLAG_SYSTEM, userId); assertEquals("Last wallpaper should be equals to current system wallpaper", lastData, wallpaper); + + final WallpaperData lastLockData = mService.mLastLockWallpaper; + final WallpaperData lockWallpaper = mService.getCurrentWallpaperData(FLAG_LOCK, userId); + assertWithMessage("Last lock wallpaper should be equals to current lock wallpaper") + .that(lastLockData) + .isEqualTo(lockWallpaper); } private void verifyDisplayData() { @@ -698,6 +926,32 @@ public class WallpaperManagerServiceTests { } /** + * Sets up mock displays for testing. + * + * <p>This method creates mock {@link Display} objects and configures the {@link DisplayManager} + * to return them. It also sets up the {@link WindowManagerInternal} to indicate that all + * displays support home. + * + * @param displayIds A list of display IDs to create mock displays for. + */ + private void setUpDisplays(List<Integer> displayIds) { + doReturn(true).when(sWindowManagerInternal).isHomeSupportedOnDisplay(anyInt()); + + Display[] mockDisplays = new Display[displayIds.size()]; + for (int i = 0; i < displayIds.size(); i++) { + final int displayId = displayIds.get(i); + final Display mockDisplay = mock(Display.class); + mockDisplays[i] = mockDisplay; + doReturn(DISPLAY_SIZE_DIMENSION).when(mockDisplay).getMaximumSizeDimension(); + doReturn(mockDisplay).when(mDisplayManager).getDisplay(eq(displayId)); + doReturn(displayId).when(mockDisplay).getDisplayId(); + doReturn(true).when(mockDisplay).hasAccess(anyInt()); + } + + doReturn(mockDisplays).when(mDisplayManager).getDisplays(); + } + + /** * Asserts that the contents of the given {@link ParcelFileDescriptor} and {@link File} contain * exactly the same bytes. * diff --git a/services/tests/security/intrusiondetection/AndroidTest.xml b/services/tests/security/intrusiondetection/AndroidTest.xml index 0d211585958a..a0e846b90f03 100644 --- a/services/tests/security/intrusiondetection/AndroidTest.xml +++ b/services/tests/security/intrusiondetection/AndroidTest.xml @@ -25,7 +25,7 @@ </target_preparer> <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> - <option name="run-command" value="setprop intrusiondetection_service_name com.android.coretests.apps.testapp/.TestLoggingService" /> + <option name="run-command" value="setprop debug.intrusiondetection_package_name com.android.coretests.apps.testapp/.TestLoggingService" /> </target_preparer> <option name="test-tag" value="IntrusionDetectionServiceTests" /> diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index e5005d1beed4..1af59daa9c78 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -33,6 +33,8 @@ import static com.android.server.accessibility.gestures.TouchState.STATE_DRAGGIN import static com.android.server.accessibility.gestures.TouchState.STATE_GESTURE_DETECTING; import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_EXPLORING; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.verify; @@ -132,10 +134,12 @@ public class TouchExplorerTest { */ private class EventCaptor implements EventStreamTransformation { List<MotionEvent> mEvents = new ArrayList<>(); + List<MotionEvent> mRawEvents = new ArrayList<>(); @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { mEvents.add(0, event.copy()); + mRawEvents.add(0, rawEvent.copy()); } @Override @@ -461,6 +465,45 @@ public class TouchExplorerTest { AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN); } + @Test + public void testSendHoverExitIfNeeded_lastSentHoverExit_noActionNeeded() { + // Prep TouchState so that the last injected hover event was a HOVER_EXIT + mTouchExplorer.getState().onInjectedMotionEvent(hoverExitEvent()); + + mTouchExplorer.sendHoverExitAndTouchExplorationGestureEndIfNeeded(/*policyFlags=*/0); + + assertNoCapturedEvents(); + } + + @Test + @EnableFlags(Flags.FLAG_EVENT_DISPATCHER_RAW_EVENT) + public void testSendHoverExitIfNeeded_lastSentHoverEnter_sendsHoverExit_withCorrectRawEvent() { + final MotionEvent rawEvent = downEvent(); + final MotionEvent modifiedEvent = hoverEnterEvent(); + // Use different display IDs just so that we can differentiate between the raw event and + // the modified event later during test assertions. + final int rawDisplayId = 123; + final int modifiedDisplayId = 456; + rawEvent.setDisplayId(rawDisplayId); + modifiedEvent.setDisplayId(modifiedDisplayId); + // Prep TouchState to track the last received modified and raw events + mTouchExplorer.getState().onReceivedMotionEvent(modifiedEvent, rawEvent, /*policyFlags=*/0); + // Prep TouchState so that the last injected hover event was not a HOVER_EXIT + mTouchExplorer.getState().onInjectedMotionEvent(modifiedEvent); + + mTouchExplorer.sendHoverExitAndTouchExplorationGestureEndIfNeeded(/*policyFlags=*/0); + + assertThat(getCapturedEvents().size()).isEqualTo(1); + assertThat(getCapturedRawEvents().size()).isEqualTo(1); + MotionEvent sentEvent = getCapturedEvents().get(0); + MotionEvent sentRawEvent = getCapturedRawEvents().get(0); + // TouchExplorer should send ACTION_HOVER_EXIT built from the last injected hover event + assertThat(sentEvent.getAction()).isEqualTo(ACTION_HOVER_EXIT); + assertThat(sentEvent.getDisplayId()).isEqualTo(modifiedDisplayId); + // ... while passing along the original raw (unmodified) event + assertThat(sentRawEvent.getDisplayId()).isEqualTo(rawDisplayId); + } + /** * Used to play back event data of a gesture by parsing the log into MotionEvents and sending * them to TouchExplorer. @@ -630,6 +673,10 @@ public class TouchExplorerTest { return ((EventCaptor) mCaptor).mEvents; } + private List<MotionEvent> getCapturedRawEvents() { + return ((EventCaptor) mCaptor).mRawEvents; + } + private MotionEvent cancelEvent() { mLastDownTime = SystemClock.uptimeMillis(); return fromTouchscreen( @@ -688,6 +735,20 @@ public class TouchExplorerTest { return event; } + private MotionEvent hoverEnterEvent() { + mLastDownTime = SystemClock.uptimeMillis(); + return fromTouchscreen( + MotionEvent.obtain( + mLastDownTime, mLastDownTime, ACTION_HOVER_ENTER, DEFAULT_X, DEFAULT_Y, 0)); + } + + private MotionEvent hoverExitEvent() { + mLastDownTime = SystemClock.uptimeMillis(); + return fromTouchscreen( + MotionEvent.obtain( + mLastDownTime, mLastDownTime, ACTION_HOVER_EXIT, DEFAULT_X, DEFAULT_Y, 0)); + } + private void moveEachPointers(MotionEvent event, PointF... points) { final float[] x = new float[points.length]; final float[] y = new float[points.length]; diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java index affcfc14034e..379079a0018c 100644 --- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java @@ -300,6 +300,22 @@ public class MediaProjectionStopControllerTest { } @Test + public void isStopReasonCallEnd_stopReasonCallEnd_returnsTrue() { + boolean result = + mStopController.isStopReasonCallEnd( + MediaProjectionStopController.STOP_REASON_CALL_END); + assertThat(result).isTrue(); + } + + @Test + public void isStopReasonCallEnd_stopReasonKeyguard_returnsFalse() { + boolean result = + mStopController.isStopReasonCallEnd( + MediaProjectionStopController.STOP_REASON_KEYGUARD); + assertThat(result).isFalse(); + } + + @Test @EnableFlags( android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS) public void testKeyguardLockedStateChanged_unlocked() { diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index 39206dcf21ef..3b32701b5169 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -1612,7 +1612,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { ); } - public void testThrottling() { + public void disabled_testThrottling() { final ShortcutInfo si1 = makeShortcut("shortcut1"); assertTrue(mManager.setDynamicShortcuts(list(si1))); @@ -1685,7 +1685,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime()); } - public void testThrottling_rewind() { + public void disabled_testThrottling_rewind() { final ShortcutInfo si1 = makeShortcut("shortcut1"); assertTrue(mManager.setDynamicShortcuts(list(si1))); @@ -1715,7 +1715,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(3, mManager.getRemainingCallCount()); } - public void testThrottling_perPackage() { + public void disabled_testThrottling_perPackage() { final ShortcutInfo si1 = makeShortcut("shortcut1"); assertTrue(mManager.setDynamicShortcuts(list(si1))); @@ -1847,7 +1847,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { }); } - public void testThrottling_foreground() throws Exception { + public void disabled_testThrottling_foreground() throws Exception { prepareCrossProfileDataSet(); dumpsysOnLogcat("Before save & load"); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java index aad06c6d6c0e..9ca2282d1d8e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java @@ -80,7 +80,7 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { genPackageAddIntent(CALLING_PACKAGE, USER_10)); } - public void testSetDynamicShortcuts_noManifestShortcuts() { + public void disabled_testSetDynamicShortcuts_noManifestShortcuts() { mManager.setDynamicShortcuts(list( shortcut("s1", A1) )); @@ -171,11 +171,12 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { .haveRanksInOrder("ms1"); } - public void testSetDynamicShortcuts_withManifestShortcuts() { - runTestWithManifestShortcuts(() -> testSetDynamicShortcuts_noManifestShortcuts()); + public void disabled_Shortcuts_withManifestShortcuts() { + runTestWithManifestShortcuts(() -> + disabled_testSetDynamicShortcuts_noManifestShortcuts()); } - public void testAddDynamicShortcuts_noManifestShortcuts() { + public void disabled_testAddDynamicShortcuts_noManifestShortcuts() { mManager.addDynamicShortcuts(list( shortcut("s1", A1) )); @@ -264,11 +265,12 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { .haveIds("s1", "s2", "s4", "s5", "s10"); } - public void testAddDynamicShortcuts_withManifestShortcuts() { - runTestWithManifestShortcuts(() -> testAddDynamicShortcuts_noManifestShortcuts()); + public void disabled_testAddDynamicShortcuts_withManifestShortcuts() { + runTestWithManifestShortcuts(() -> + disabled_testAddDynamicShortcuts_noManifestShortcuts()); } - public void testUpdateShortcuts_noManifestShortcuts() { + public void disabled_testUpdateShortcuts_noManifestShortcuts() { mManager.addDynamicShortcuts(list( shortcut("s5", A1, 0), shortcut("s4", A1), @@ -374,11 +376,12 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { .haveIds("s3", "s2"); } - public void testUpdateShortcuts_withManifestShortcuts() { - runTestWithManifestShortcuts(() -> testUpdateShortcuts_noManifestShortcuts()); + public void disabled_testUpdateShortcuts_withManifestShortcuts() { + runTestWithManifestShortcuts(() -> + disabled_testUpdateShortcuts_noManifestShortcuts()); } - public void testDeleteDynamicShortcuts_noManifestShortcuts() { + public void disabled_testDeleteDynamicShortcuts_noManifestShortcuts() { mManager.addDynamicShortcuts(list( shortcut("s5", A1, 0), shortcut("s4", A1), @@ -435,11 +438,12 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { .haveIds("s2", "s4"); } - public void testDeleteDynamicShortcuts_withManifestShortcuts() { - runTestWithManifestShortcuts(() -> testDeleteDynamicShortcuts_noManifestShortcuts()); + public void disabled_testDeleteDynamicShortcuts_withManifestShortcuts() { + runTestWithManifestShortcuts(() -> + disabled_testDeleteDynamicShortcuts_noManifestShortcuts()); } - public void testDisableShortcuts_noManifestShortcuts() { + public void disabled_testDisableShortcuts_noManifestShortcuts() { mManager.addDynamicShortcuts(list( shortcut("s5", A1, 0), shortcut("s4", A1), @@ -508,8 +512,9 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { .haveIds("s4", "x2"); } - public void testDisableShortcuts_withManifestShortcuts() { - runTestWithManifestShortcuts(() -> testDisableShortcuts_noManifestShortcuts()); + public void disabled_testDisableShortcuts_withManifestShortcuts() { + runTestWithManifestShortcuts(() -> + disabled_testDisableShortcuts_noManifestShortcuts()); } public void testGetSharingShortcutCount() { diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java index 400d3a891a8d..5562e3d7c532 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java @@ -66,7 +66,7 @@ public class ShortcutManagerTest5 extends BaseShortcutManagerTest { mMyUserId = android.os.Process.myUserHandle().getIdentifier(); } - public void testGetPackageUid() { + public void disabled_testGetPackageUid() { assertTrue(mShortcutService.injectGetPackageUid( mMyPackage, mMyUserId) != 0); @@ -74,7 +74,7 @@ public class ShortcutManagerTest5 extends BaseShortcutManagerTest { "no.such.package", mMyUserId)); } - public void testGetPackageInfo() { + public void disabled_testGetPackageInfo() { PackageInfo pi = mShortcutService.getPackageInfo( mMyPackage, mMyUserId, /*signature*/ false); assertEquals(mMyPackage, pi.packageName); @@ -132,7 +132,7 @@ public class ShortcutManagerTest5 extends BaseShortcutManagerTest { meta.close(); } - public void testGetInstalledPackages() { + public void disabled_testGetInstalledPackages() { List<PackageInfo> apks = mShortcutService.getInstalledPackages(mMyUserId); Set<String> expectedPackages = set("com.android.settings", mMyPackage); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java index 7f7a4ae13245..306f908258d1 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java @@ -26,7 +26,7 @@ import androidx.test.filters.SmallTest; @Presubmit @SmallTest public class ShortcutManagerTest6 extends BaseShortcutManagerTest { - public void testHasShortcutHostPermissionInner_with3pLauncher_complicated() { + public void disabled_testHasShortcutHostPermissionInner_with3pLauncher_complicated() { // Set the default launcher. prepareGetRoleHoldersAsUser(CALLING_PACKAGE_2, USER_10); assertFalse(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_10)); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java index 86bde837bfe1..5a89db143b34 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java @@ -100,7 +100,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { assertEquals(99, mService.mMaxUpdatesPerInterval); } - public void testRoot() throws Exception { + public void disabled_testRoot() throws Exception { mService.mMaxUpdatesPerInterval = 99; mInjectedCallingUid = Process.ROOT_UID; @@ -128,7 +128,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { assertEquals(1, mService.mMaxUpdatesPerInterval); } - public void testResetThrottling() throws Exception { + public void disabled_testResetThrottling() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -149,7 +149,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { }); } - public void testResetThrottling_user_not_running() throws Exception { + public void disabled_testResetThrottling_user_not_running() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -177,7 +177,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { }); } - public void testResetThrottling_user_running() throws Exception { + public void disabled_testResetThrottling_user_running() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -201,7 +201,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { }); } - public void testResetAllThrottling() throws Exception { + public void disabled_testResetAllThrottling() throws Exception { prepareCrossProfileDataSet(); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { @@ -262,7 +262,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { "Launcher: ComponentInfo{com.android.test.1/name}"); } - public void testUnloadUser() throws Exception { + public void disabled_testUnloadUser() throws Exception { prepareCrossProfileDataSet(); assertNotNull(mService.getShortcutsForTest().get(USER_11)); @@ -276,7 +276,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { assertNull(mService.getShortcutsForTest().get(USER_11)); } - public void testClearShortcuts() throws Exception { + public void disabled_testClearShortcuts() throws Exception { mRunningUsers.put(USER_11, true); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java index 9b02a3abf14b..5c2132f0e0e9 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java @@ -84,7 +84,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { makeCallerForeground(); } - public void testGetParentOrSelfUserId() { + public void disabled_testGetParentOrSelfUserId() { assertEquals(USER_10, mService.getParentOrSelfUserId(USER_10)); assertEquals(USER_11, mService.getParentOrSelfUserId(USER_11)); assertEquals(USER_12, mService.getParentOrSelfUserId(USER_12)); @@ -222,7 +222,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { actualIntent.getFlags()); } - public void testNotForeground() { + public void disabled_testNotForeground() { setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 43302264964e..edfdb4ffec3a 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -253,7 +253,6 @@ import android.media.AudioAttributes; import android.media.AudioManager; import android.media.session.MediaSession; import android.net.ConnectivityManager; -import android.net.Network; import android.net.NetworkCapabilities; import android.net.Uri; import android.os.Binder; @@ -571,6 +570,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Mock NotificationAttentionHelper mAttentionHelper; + @Mock + NetworkCapabilities mWifiNetworkCapabilities; + private NotificationManagerService.WorkerHandler mWorkerHandler; private class TestableToastCallback extends ITransientNotification.Stub { @@ -771,7 +773,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mActivityIntentImmutable = spy(PendingIntent.getActivity(mContext, 0, new Intent().setPackage(mPkg), FLAG_IMMUTABLE)); - when(mConnectivityManager.getActiveNetwork()).thenReturn(null); + when(mWifiNetworkCapabilities.hasTransport(eq(NetworkCapabilities.TRANSPORT_WIFI))) + .thenReturn(true); + when(mWifiNetworkCapabilities + .hasCapability(eq(NetworkCapabilities.NET_CAPABILITY_VALIDATED))) + .thenReturn(true); + when(mWifiNetworkCapabilities + .hasCapability(eq(NetworkCapabilities.NET_CAPABILITY_TRUSTED))) + .thenReturn(true); initNMS(); } @@ -14391,13 +14400,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testMakeRankingUpdate_clearsHasSensitiveContentIfConnectedToWifi() { mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS, FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN); - when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class)); - when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn( - new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .build() - ); - mService.updateWifiConnectionState(); + mService.updateWifiConnectionState(mWifiNetworkCapabilities); when(mListeners.hasSensitiveContent(any())).thenReturn(true); NotificationRecord pkgA = new NotificationRecord(mContext, generateSbn("a", 1000, 9, 0), mTestNotificationChannel); @@ -14416,13 +14419,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testMakeRankingUpdate_doesntClearHasSensitiveContentIfNotConnectedToWifi() { mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS, FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN); - when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class)); - when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn( - new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .build() - ); - mService.updateWifiConnectionState(); + mService.updateWifiConnectionState(mock(NetworkCapabilities.class)); when(mListeners.hasSensitiveContent(any())).thenReturn(true); NotificationRecord record = getSensitiveNotificationRecord(); mService.addNotification(record); @@ -14440,13 +14437,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testMakeRankingUpdate_doesntClearHasSensitiveContentIfNotSysUi() { mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN); - when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class)); - when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn( - new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .build() - ); - mService.updateWifiConnectionState(); + mService.updateWifiConnectionState(mWifiNetworkCapabilities); when(mListeners.hasSensitiveContent(any())).thenReturn(true); NotificationRecord record = getSensitiveNotificationRecord(); mService.addNotification(record); @@ -14463,13 +14454,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testMakeRankingUpdate_doesntClearHasSensitiveContentIfFlagDisabled() { mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN); - when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class)); - when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn( - new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .build() - ); - mService.updateWifiConnectionState(); + mService.updateWifiConnectionState(mWifiNetworkCapabilities); when(mListeners.hasSensitiveContent(any())).thenReturn(true); NotificationRecord record = getSensitiveNotificationRecord(); mService.addNotification(record); diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java index ff8b6d3c1962..08eb1451bd6f 100644 --- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java @@ -23,6 +23,8 @@ import static android.view.KeyEvent.KEYCODE_POWER; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.hardware.input.Flags.FLAG_ABORT_SLOW_MULTI_PRESS; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -35,9 +37,13 @@ import android.os.HandlerThread; import android.os.Looper; import android.os.Process; import android.os.SystemClock; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.view.KeyEvent; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import java.util.concurrent.BlockingQueue; @@ -52,6 +58,8 @@ import java.util.concurrent.TimeUnit; * atest WmTests:SingleKeyGestureTests */ public class SingleKeyGestureTests { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private SingleKeyGestureDetector mDetector; private int mMaxMultiPressCount = 3; @@ -260,6 +268,44 @@ public class SingleKeyGestureTests { } @Test + @EnableFlags(FLAG_ABORT_SLOW_MULTI_PRESS) + public void testMultipress_noLongPressBehavior_longPressCancelsMultiPress() + throws InterruptedException { + mLongPressOnPowerBehavior = false; + + pressKey(KEYCODE_POWER, 0 /* pressTime */); + pressKey(KEYCODE_POWER, mLongPressTime /* pressTime */); + + assertFalse(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS)); + } + + @Test + @EnableFlags(FLAG_ABORT_SLOW_MULTI_PRESS) + public void testMultipress_noVeryLongPressBehavior_veryLongPressCancelsMultiPress() + throws InterruptedException { + mLongPressOnPowerBehavior = false; + mVeryLongPressOnPowerBehavior = false; + + pressKey(KEYCODE_POWER, 0 /* pressTime */); + pressKey(KEYCODE_POWER, mVeryLongPressTime /* pressTime */); + + assertFalse(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS)); + } + + @Test + @DisableFlags(FLAG_ABORT_SLOW_MULTI_PRESS) + public void testMultipress_flagDisabled_noLongPressBehavior_longPressDoesNotCancelMultiPress() + throws InterruptedException { + mLongPressOnPowerBehavior = false; + mExpectedMultiPressCount = 2; + + pressKey(KEYCODE_POWER, 0 /* pressTime */); + pressKey(KEYCODE_POWER, mLongPressTime /* pressTime */); + + assertTrue(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS)); + } + + @Test public void testMultiPress() throws InterruptedException { // Double presses. mExpectedMultiPressCount = 2; diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index d3f98d1a1d70..0b3d720bf52a 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -3219,7 +3219,6 @@ public class CarrierConfigManager { * The roaming indicator will be shown if this is {@code true} and will not be shown if this is * {@code false}. */ - @FlaggedApi(Flags.FLAG_HIDE_ROAMING_ICON) public static final String KEY_SHOW_ROAMING_INDICATOR_BOOL = "show_roaming_indicator_bool"; /** diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java index 2d650ab20802..bb9e7065b154 100644 --- a/telephony/java/android/telephony/PreciseDisconnectCause.java +++ b/telephony/java/android/telephony/PreciseDisconnectCause.java @@ -326,6 +326,13 @@ public final class PreciseDisconnectCause { @Deprecated public static final int CDMA_ACCESS_BLOCKED = 1009; + /** Call was disconnected with cause code retry over volte. */ + @FlaggedApi(Flags.FLAG_ADD_IMS_REDIAL_CODES_FOR_EMERGENCY_CALLS) + public static final int EMERGENCY_REDIAL_ON_IMS = 3001; + /** Call was disconnected with cause code retry over vowifi. */ + @FlaggedApi(Flags.FLAG_ADD_IMS_REDIAL_CODES_FOR_EMERGENCY_CALLS) + public static final int EMERGENCY_REDIAL_ON_VOWIFI = 3002; + /* OEM specific error codes. To be used by OEMs when they don't want to reveal error code which would be replaced by ERROR_UNSPECIFIED */ public static final int OEM_CAUSE_1 = 0xf001; diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index da4165553e57..6d32303fb13b 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -2447,6 +2447,7 @@ public class TelephonyManager { * as follows: * * <ul> + * <li>If the device is running Android 25Q2 or later, then null is returned.</li> * <li>If the calling app's target SDK is API level 28 or lower and the app has the * READ_PHONE_STATE permission then null is returned.</li> * <li>If the calling app's target SDK is API level 28 or lower and the app does not have @@ -2455,7 +2456,8 @@ public class TelephonyManager { * </ul> * * @deprecated Legacy CDMA is unsupported. - * @throws UnsupportedOperationException If the device does not have + * @throws UnsupportedOperationException If the device is running + * Android 25Q1 or earlier and does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. */ @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 567314beadd3..5daa29b940bf 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -130,10 +130,10 @@ public class ApnSetting implements Parcelable { public static final int TYPE_RCS = ApnTypes.RCS; /** APN type for OEM_PAID networks (Automotive PANS) */ @FlaggedApi(Flags.FLAG_OEM_PAID_PRIVATE) - public static final int TYPE_OEM_PAID = 1 << 16; // TODO(b/366194627): ApnTypes.OEM_PAID; + public static final int TYPE_OEM_PAID = ApnTypes.OEM_PAID; /** APN type for OEM_PRIVATE networks (Automotive PANS) */ @FlaggedApi(Flags.FLAG_OEM_PAID_PRIVATE) - public static final int TYPE_OEM_PRIVATE = 1 << 17; // TODO(b/366194627): ApnTypes.OEM_PRIVATE; + public static final int TYPE_OEM_PRIVATE = ApnTypes.OEM_PRIVATE; /** @hide */ @IntDef(flag = true, prefix = {"TYPE_"}, value = { diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt index d75a8f433af8..40f4f1ab0791 100644 --- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt +++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt @@ -314,7 +314,17 @@ class InputManagerServiceTests { } } - private fun createVirtualDisplays(count: Int): List<VirtualDisplay> { + private class AutoClosingVirtualDisplays(val displays: List<VirtualDisplay>) : AutoCloseable { + operator fun get(i: Int): VirtualDisplay = displays[i] + + override fun close() { + for (display in displays) { + display.release() + } + } + } + + private fun createVirtualDisplays(count: Int): AutoClosingVirtualDisplays { val displayManager: DisplayManager = context.getSystemService( DisplayManager::class.java ) as DisplayManager @@ -329,7 +339,7 @@ class InputManagerServiceTests { /* flags= */ 0 )) } - return virtualDisplays + return AutoClosingVirtualDisplays(virtualDisplays) } // Helper function that creates a KeyEvent with Keycode A with the given action @@ -374,50 +384,51 @@ class InputManagerServiceTests { val mockSurfaceHolder2 = mock(SurfaceHolder::class.java) `when`(mockSurfaceView2.holder).thenReturn(mockSurfaceHolder2) - val virtualDisplays = createVirtualDisplays(2) + createVirtualDisplays(2).use { virtualDisplays -> + // Simulate an InputDevice + val inputDevice = createInputDevice() - // Simulate an InputDevice - val inputDevice = createInputDevice() - - // Associate input device with display - service.addUniqueIdAssociationByDescriptor( - inputDevice.descriptor, - virtualDisplays[0].display.displayId.toString() - ) + // Associate input device with display + service.addUniqueIdAssociationByDescriptor( + inputDevice.descriptor, + virtualDisplays[0].display.displayId.toString() + ) - // Simulate 2 different KeyEvents - val downEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_DOWN) - val upEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_UP) + // Simulate 2 different KeyEvents + val downEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_DOWN) + val upEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_UP) - // Create a mock OnKeyListener object - val mockOnKeyListener = mock(OnKeyListener::class.java) + // Create a mock OnKeyListener object + val mockOnKeyListener = mock(OnKeyListener::class.java) - // Verify that the event went to Display 1 not Display 2 - service.injectInputEvent(downEvent, InputEventInjectionSync.NONE) + // Verify that the event went to Display 1 not Display 2 + service.injectInputEvent(downEvent, InputEventInjectionSync.NONE) - // Call the onKey method on the mock OnKeyListener object - mockOnKeyListener.onKey(mockSurfaceView1, /* keyCode= */ KeyEvent.KEYCODE_A, downEvent) - mockOnKeyListener.onKey(mockSurfaceView2, /* keyCode= */ KeyEvent.KEYCODE_A, upEvent) + // Call the onKey method on the mock OnKeyListener object + mockOnKeyListener.onKey(mockSurfaceView1, /* keyCode= */ KeyEvent.KEYCODE_A, downEvent) + mockOnKeyListener.onKey(mockSurfaceView2, /* keyCode= */ KeyEvent.KEYCODE_A, upEvent) - // Verify that the onKey method was called with the expected arguments - verify(mockOnKeyListener).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, downEvent) - verify(mockOnKeyListener, never()).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, downEvent) + // Verify that the onKey method was called with the expected arguments + verify(mockOnKeyListener).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, downEvent) + verify(mockOnKeyListener, never()) + .onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, downEvent) - // Remove association - service.removeUniqueIdAssociationByDescriptor(inputDevice.descriptor) + // Remove association + service.removeUniqueIdAssociationByDescriptor(inputDevice.descriptor) - // Associate with Display 2 - service.addUniqueIdAssociationByDescriptor( - inputDevice.descriptor, - virtualDisplays[1].display.displayId.toString() - ) + // Associate with Display 2 + service.addUniqueIdAssociationByDescriptor( + inputDevice.descriptor, + virtualDisplays[1].display.displayId.toString() + ) - // Simulate a KeyEvent - service.injectInputEvent(upEvent, InputEventInjectionSync.NONE) + // Simulate a KeyEvent + service.injectInputEvent(upEvent, InputEventInjectionSync.NONE) - // Verify that the event went to Display 2 not Display 1 - verify(mockOnKeyListener).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, upEvent) - verify(mockOnKeyListener, never()).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, upEvent) + // Verify that the event went to Display 2 not Display 1 + verify(mockOnKeyListener).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, upEvent) + verify(mockOnKeyListener, never()).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, upEvent) + } } @Test @@ -436,50 +447,51 @@ class InputManagerServiceTests { val mockSurfaceHolder2 = mock(SurfaceHolder::class.java) `when`(mockSurfaceView2.holder).thenReturn(mockSurfaceHolder2) - val virtualDisplays = createVirtualDisplays(2) + createVirtualDisplays(2).use { virtualDisplays -> + // Simulate an InputDevice + val inputDevice = createInputDevice() - // Simulate an InputDevice - val inputDevice = createInputDevice() - - // Associate input device with display - service.addUniqueIdAssociationByPort( - inputDevice.name, - virtualDisplays[0].display.displayId.toString() - ) + // Associate input device with display + service.addUniqueIdAssociationByPort( + inputDevice.name, + virtualDisplays[0].display.displayId.toString() + ) - // Simulate 2 different KeyEvents - val downEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_DOWN) - val upEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_UP) + // Simulate 2 different KeyEvents + val downEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_DOWN) + val upEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_UP) - // Create a mock OnKeyListener object - val mockOnKeyListener = mock(OnKeyListener::class.java) + // Create a mock OnKeyListener object + val mockOnKeyListener = mock(OnKeyListener::class.java) - // Verify that the event went to Display 1 not Display 2 - service.injectInputEvent(downEvent, InputEventInjectionSync.NONE) + // Verify that the event went to Display 1 not Display 2 + service.injectInputEvent(downEvent, InputEventInjectionSync.NONE) - // Call the onKey method on the mock OnKeyListener object - mockOnKeyListener.onKey(mockSurfaceView1, /* keyCode= */ KeyEvent.KEYCODE_A, downEvent) - mockOnKeyListener.onKey(mockSurfaceView2, /* keyCode= */ KeyEvent.KEYCODE_A, upEvent) + // Call the onKey method on the mock OnKeyListener object + mockOnKeyListener.onKey(mockSurfaceView1, /* keyCode= */ KeyEvent.KEYCODE_A, downEvent) + mockOnKeyListener.onKey(mockSurfaceView2, /* keyCode= */ KeyEvent.KEYCODE_A, upEvent) - // Verify that the onKey method was called with the expected arguments - verify(mockOnKeyListener).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, downEvent) - verify(mockOnKeyListener, never()).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, downEvent) + // Verify that the onKey method was called with the expected arguments + verify(mockOnKeyListener).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, downEvent) + verify(mockOnKeyListener, never()) + .onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, downEvent) - // Remove association - service.removeUniqueIdAssociationByPort(inputDevice.name) + // Remove association + service.removeUniqueIdAssociationByPort(inputDevice.name) - // Associate with Display 2 - service.addUniqueIdAssociationByPort( - inputDevice.name, - virtualDisplays[1].display.displayId.toString() - ) + // Associate with Display 2 + service.addUniqueIdAssociationByPort( + inputDevice.name, + virtualDisplays[1].display.displayId.toString() + ) - // Simulate a KeyEvent - service.injectInputEvent(upEvent, InputEventInjectionSync.NONE) + // Simulate a KeyEvent + service.injectInputEvent(upEvent, InputEventInjectionSync.NONE) - // Verify that the event went to Display 2 not Display 1 - verify(mockOnKeyListener).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, upEvent) - verify(mockOnKeyListener, never()).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, upEvent) + // Verify that the event went to Display 2 not Display 1 + verify(mockOnKeyListener).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, upEvent) + verify(mockOnKeyListener, never()).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, upEvent) + } } @Test diff --git a/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt index 9e0f7347943d..bc0b7a5c816c 100644 --- a/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt +++ b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt @@ -29,6 +29,7 @@ import android.view.MotionEvent import androidx.test.platform.app.InstrumentationRegistry import com.android.cts.input.BatchedEventSplitter import com.android.cts.input.CaptureEventActivity +import com.android.cts.input.DebugInputRule import com.android.cts.input.InputJsonParser import com.android.cts.input.VirtualDisplayActivityScenario import com.android.cts.input.inputeventmatchers.isResampled @@ -97,6 +98,10 @@ class UinputRecordingIntegrationTests { private lateinit var instrumentation: Instrumentation private lateinit var parser: InputJsonParser + + @get:Rule + val debugInputRule = DebugInputRule() + @get:Rule val testName = TestName() @@ -109,6 +114,7 @@ class UinputRecordingIntegrationTests { parser = InputJsonParser(instrumentation.context) } + @DebugInputRule.DebugInput(bug = 389901828) @Test fun testEvemuRecording() { VirtualDisplayActivityScenario.AutoClose<CaptureEventActivity>( diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java index 9e029a8d5e57..72b1780ceb06 100644 --- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java +++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java @@ -33,6 +33,7 @@ import org.junit.runners.JUnit4; import perfetto.protos.ProtologCommon; import java.io.File; +import java.io.IOException; @Presubmit @RunWith(JUnit4.class) @@ -159,4 +160,14 @@ public class ProtoLogViewerConfigReaderTest { loadViewerConfig(); unloadViewerConfig(); } + + @Test + public void testMessageHashIsAvailableInFile() throws IOException { + Truth.assertThat(mConfig.messageHashIsAvailableInFile(1)).isTrue(); + Truth.assertThat(mConfig.messageHashIsAvailableInFile(2)).isTrue(); + Truth.assertThat(mConfig.messageHashIsAvailableInFile(3)).isTrue(); + Truth.assertThat(mConfig.messageHashIsAvailableInFile(4)).isTrue(); + Truth.assertThat(mConfig.messageHashIsAvailableInFile(5)).isTrue(); + Truth.assertThat(mConfig.messageHashIsAvailableInFile(6)).isFalse(); + } } diff --git a/tools/aapt2/tools/finalize_res.py b/tools/aapt2/tools/finalize_res.py index 0e4d865bc890..f9add7d90125 100755 --- a/tools/aapt2/tools/finalize_res.py +++ b/tools/aapt2/tools/finalize_res.py @@ -38,13 +38,20 @@ Usage: $ANDROID_BUILD_TOP/frameworks/base/tools/aapt2/tools/finalize_res.py \ import re import sys +import subprocess +from collections import defaultdict resTypes = ["attr", "id", "style", "string", "dimen", "color", "array", "drawable", "layout", "anim", "animator", "interpolator", "mipmap", "integer", "transition", "raw", "bool", "fraction"] +_aconfig_map = {} +_not_finalized = defaultdict(list) _type_ids = {} _type = "" +_finalized_flags = set() +_non_finalized_flags = set() + _lowest_staging_first_id = 0x01FFFFFF @@ -53,13 +60,48 @@ _lowest_staging_first_id = 0x01FFFFFF prefixed with removed_. The IDs are assigned without holes starting from the last ID for that type currently finalized in public-final.xml. """ -def finalize_item(raw): - name = raw.group(1) - if re.match(r'_*removed.+', name): - return "" +def finalize_item(comment_and_item): + print("Processing:\n" + comment_and_item) + name = re.search('<public name="(.+?)"',comment_and_item, flags=re.DOTALL).group(1) + if re.match('removed_.+', name): + # Remove it from <staging-public-group> in public-staging.xml + # Include it as is in <staging-public-group-final> in public-final.xml + # Don't assign an id in public-final.xml + return ("", comment_and_item, "") + + comment = re.search(' *<!--.+?-->\n', comment_and_item, flags=re.DOTALL).group(0) + + flag = re.search('<!-- @FlaggedApi\((.+?)\)', comment, flags=re.DOTALL).group(1) + if flag.startswith("\""): + # Flag is a string value, just remove " + flag = flag.replace("\"", "") + else: + # Flag is a java constant, convert to string value + flag = flag.replace(".Flags.FLAG_", ".").lower() + + if flag not in _aconfig_map: + raise Exception("Unknown flag: " + flag) + + # READ_ONLY-ENABLED is a magic string from printflags output below + if _aconfig_map[flag] != "READ_ONLY-ENABLED": + _non_finalized_flags.add(flag) + # Keep it as is in <staging-public-group> in public-staging.xml + # Include as magic constant "removed_" in <staging-public-group-final> in public-final.xml + # Don't assign an id in public-final.xml + return (comment_and_item, " <public name=\"removed_\" />\n", "") + + _finalized_flags.add(flag) + id = _type_ids[_type] _type_ids[_type] += 1 - return ' <public type="%s" name="%s" id="%s" />\n' % (_type, name, '0x{0:0{1}x}'.format(id, 8)) + + # Removes one indentation step to align the comment with the item outside the + comment = re.sub("^ ", "", comment, flags=re.MULTILINE) + + # Remove from <staging-public-group> in public-staging.xml + # Include as is in <staging-public-group-final> in public-final.xml + # Assign an id in public-final.xml + return ("", comment_and_item, comment + ' <public type="%s" name="%s" id="%s" />\n' % (_type, name, '0x{0:0{1}x}'.format(id, 8))) """ @@ -72,10 +114,26 @@ def finalize_group(raw): _type = raw.group(1) id = int(raw.group(2), 16) _type_ids[_type] = _type_ids.get(_type, id) - (res, count) = re.subn(' {0,4}<public name="(.+?)" */>\n', finalize_item, raw.group(3)) - if count > 0: - res = raw.group(0).replace("staging-public-group", - "staging-public-group-final") + '\n' + res + + + all = re.findall(' *<!--.*?<public name=".+?" */>\n', raw.group(3), flags=re.DOTALL) + res = "" + group_matches = "" + for match in all: + (staging_group, final_group, final_id_assignment) = finalize_item(match) + + if staging_group: + _not_finalized[_type].append(staging_group) + + if final_group: + group_matches += final_group + + if final_id_assignment: + res += final_id_assignment + + # Only add it to final.xml if new ids were actually assigned + if res: + res = '<staging-public-group-final type="%s" first-id="%s">\n%s </staging-public-group-final>\n\n%s' % (_type, raw.group(2), group_matches, res) _lowest_staging_first_id = min(id, _lowest_staging_first_id) return res @@ -88,6 +146,13 @@ def collect_ids(raw): id = int(m.group(2), 16) _type_ids[type] = max(id + 1, _type_ids.get(type, 0)) +# This is a hack and assumes this script is run from the top directory +output=subprocess.run("printflags --format='{fully_qualified_name} {permission}-{state}'", shell=True, capture_output=True, encoding="utf-8", check=True) +for line in output.stdout.splitlines(): + parts = line.split() + key = parts[0] + value = parts[1] + _aconfig_map[key]=value with open(sys.argv[1], "r+") as stagingFile: with open(sys.argv[2], "r+") as finalFile: @@ -132,10 +197,21 @@ with open(sys.argv[1], "r+") as stagingFile: nextId = _lowest_staging_first_id - 0x00010000 for resType in resTypes: stagingFile.write(' <staging-public-group type="%s" first-id="%s">\n' - ' </staging-public-group>\n\n' % - (resType, '0x{0:0{1}x}'.format(nextId, 8))) + % (resType, '0x{0:0{1}x}'.format(nextId, 8))) + for item in _not_finalized[resType]: + stagingFile.write(item) + stagingFile.write(' </staging-public-group>\n\n') nextId -= 0x00010000 # Close the resources tag and truncate, since the file will be shorter than the previous stagingFile.write("</resources>\n") stagingFile.truncate() + + +print("\nFlags that had resources that were NOT finalized:") +for flag in sorted(_non_finalized_flags): + print(flag) + +print("\nFlags that had resources that were finalized:") +for flag in sorted(_finalized_flags): + print(flag) diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt index af753e5963a3..b62843ca3ff4 100644 --- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt +++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt @@ -19,6 +19,7 @@ package com.google.android.lint import com.android.tools.lint.client.api.IssueRegistry import com.android.tools.lint.client.api.Vendor import com.android.tools.lint.detector.api.CURRENT_API +import com.google.android.lint.multiuser.PendingIntentGetActivityDetector import com.google.android.lint.parcel.SaferParcelChecker import com.google.auto.service.AutoService @@ -40,6 +41,7 @@ class AndroidFrameworkIssueRegistry : IssueRegistry() { PermissionMethodDetector.ISSUE_PERMISSION_METHOD_USAGE, PermissionMethodDetector.ISSUE_CAN_BE_PERMISSION_METHOD, FeatureAutomotiveDetector.ISSUE, + PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY, ) override val api: Int diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetector.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetector.kt new file mode 100644 index 000000000000..b9f22ebfa8ec --- /dev/null +++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetector.kt @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2025 The Android Open 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.google.android.lint.multiuser + +import com.android.tools.lint.detector.api.Category +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Issue +import com.android.tools.lint.detector.api.JavaContext +import com.android.tools.lint.detector.api.Scope +import com.android.tools.lint.detector.api.Severity +import com.android.tools.lint.detector.api.SourceCodeScanner +import com.intellij.psi.PsiMethod +import java.util.EnumSet +import org.jetbrains.uast.UCallExpression + +/** + * Detector for flagging potential multiuser issues in `PendingIntent.getActivity()` calls. + * + * This detector checks for calls to `PendingIntent#getActivity()` and + * reports a warning if such a call is found, suggesting that the + * default user 0 context might not be the right one. + */ +class PendingIntentGetActivityDetector : Detector(), SourceCodeScanner { + + companion object { + + val description = """Flags potential multiuser issue in PendingIntent.getActivity() calls.""" + + val EXPLANATION = + """ + **Problem:** + + Calling `PendingIntent.getActivity()` in the `system_server` often accidentally uses the user 0 context. Moreover, since there's no explicit user parameter in the `getActivity` method, it can be hard to tell which user the `PendingIntent` activity is associated with, making the code error-prone and less readable. + + **Solution:** + + Always use the user aware methods to refer the correct user context. You can achieve this by: + + * **Using `PendingIntent.getActivityAsUser(...)`:** This API allows you to explicitly specify the user for the activity. + + ```java + PendingIntent.getActivityAsUser( + mContext, /*requestCode=*/0, intent, + PendingIntent.FLAG_IMMUTABLE, /*options=*/null, + UserHandle.of(mUserId)); + ``` + + **When to Ignore this Warning:** + + You can safely ignore this warning if you are certain that: + + * You've confirmed that the `PendingIntent` activity you're targeting is the correct one and is **rightly** associated with the context parameter passed into the `PendingIntent.getActivity` method. + + **Note:** If you are unsure about the user context, it's best to err on the side of caution and explicitly specify the user using the method specified above. + + **For any further questions, please reach out to go/multiuser-help.** + """.trimIndent() + + val ISSUE_PENDING_INTENT_GET_ACTIVITY: Issue = + Issue.create( + id = "PendingIntent#getActivity", + briefDescription = description, + explanation = EXPLANATION, + category = Category.SECURITY, + priority = 8, + severity = Severity.WARNING, + implementation = + Implementation( + PendingIntentGetActivityDetector::class.java, + EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES), + ), + ) + } + + override fun getApplicableMethodNames() = listOf("getActivity") + + override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) { + // Check if the method call is PendingIntent.getActivity + if ( + context.evaluator.isMemberInClass(method, "android.app.PendingIntent") && + method.name == "getActivity" + ) { + context.report( + ISSUE_PENDING_INTENT_GET_ACTIVITY, + node, + context.getLocation(node), + "Using `PendingIntent.getActivity(...)` might not be multiuser-aware. " + + "Consider using the user aware method `PendingIntent.getActivityAsUser(...)`.", + ) + } + } +} diff --git a/tools/lint/framework/checks/src/test/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetectorTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetectorTest.kt new file mode 100644 index 000000000000..401055055232 --- /dev/null +++ b/tools/lint/framework/checks/src/test/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetectorTest.kt @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2025 The Android Open 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.google.android.lint.multiuser + +import com.android.tools.lint.checks.infrastructure.LintDetectorTest +import com.android.tools.lint.checks.infrastructure.TestFile +import com.android.tools.lint.checks.infrastructure.TestLintTask +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Issue + +@Suppress("UnstableApiUsage") +class PendingIntentGetActivityDetectorTest : LintDetectorTest() { + + override fun getDetector(): Detector = PendingIntentGetActivityDetector() + + override fun getIssues(): List<Issue> = + listOf(PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY) + + override fun lint(): TestLintTask = super.lint().allowMissingSdk(true) + + fun testPendingIntentGetActivity() { + lint() + .files( + java( + """ + package test.pkg; + + import android.app.PendingIntent; + import android.content.Context; + import android.content.Intent; + + public class TestClass { + private Context mContext; + + public void testMethod(Intent intent) { + PendingIntent.getActivity( + mContext, /*requestCode=*/0, intent, + PendingIntent.FLAG_IMMUTABLE, /*options=*/null + ); + } + } + """ + ) + .indented(), + *stubs, + ) + .issues(PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY) + .run() + .expect( + """ + src/test/pkg/TestClass.java:11: Warning: Using PendingIntent.getActivity(...) might not be multiuser-aware. Consider using the user aware method PendingIntent.getActivityAsUser(...). [PendingIntent#getActivity] + PendingIntent.getActivity( + ^ + 0 errors, 1 warnings + """ + ) + } + + fun testPendingIntentGetActivityAsUser() { + lint() + .files( + java( + """ + package test.pkg; + + import android.app.PendingIntent; + import android.content.Context; + import android.content.Intent; + import android.os.UserHandle; + + public class TestClass { + private Context mContext; + + public void testMethod(Intent intent) { + PendingIntent.getActivityAsUser( + mContext, /*requestCode=*/0, intent, + 0, /*options=*/null, + UserHandle.CURRENT + ); + } + } + """ + ) + .indented(), + *stubs, + ) + .issues(PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY) + .run() + .expectClean() + } + + private val pendingIntentStub: TestFile = + java( + """ + package android.app; + + import android.content.Context; + import android.content.Intent; + import android.os.UserHandle; + + public class PendingIntent { + public static boolean getActivity(Context context, int requestCode, Intent intent, int flags) { + return true; + } + + public static boolean getActivityAsUser( + Context context, + int requestCode, + Intent intent, + int flags, + UserHandle userHandle + ) { + return true; + } + } + """ + ) + + private val contxtStub: TestFile = + java( + """ + package android.content; + + import android.os.UserHandle; + + public class Context { + + public Context createContextAsUser(UserHandle userHandle, int flags) { + return this; + } + } + + """ + ) + + private val userHandleStub: TestFile = + java( + """ + package android.os; + + public class UserHandle { + + } + + """ + ) + + private val intentStub: TestFile = + java( + """ + package android.content; + + public class Intent { + + } + """ + ) + + private val stubs = arrayOf(pendingIntentStub, contxtStub, userHandleStub, intentStub) +} |